; Check http://editorconfig.org/ for more informations
-; Top-most EditorConfig file
root = true
-; tab indentation
[*]
indent_style = tab
+tab_width = 8
trim_trailing_whitespace = true
insert_final_newline = true
-; 4-column space indentation
+[*.yml]
+indent_style = space
+indent_size = 2
+
[*.md]
indent_style = space
indent_size = 4
trim_trailing_whitespace = false
+
+[*.py]
+indent_style = space
+indent_size = 4
--- /dev/null
+# Continuous integration and pull request validation builds for the
+# master and maintenance branches.
+name: CI Build
+
+on:
+ push:
+ branches: [ master, maint/* ]
+ pull_request:
+ branches: [ master, maint/* ]
+
+env:
+ docker-registry: docker.pkg.github.com
+ docker-config-path: azure-pipelines/docker
+
+jobs:
+ # Build the docker container images that we will use for our Linux
+ # builds. This will identify the last commit to the repository that
+ # updated the docker images, and try to download the image tagged with
+ # that sha. If it does not exist, we'll do a docker build and push
+ # the image up to GitHub Packages for the actual CI/CD runs. We tag
+ # with both the sha and "latest" so that the subsequent runs need not
+ # know the sha. Only do this on CI builds (when the event is a "push")
+ # because PR builds from forks lack permission to write packages.
+ build_containers:
+ name: Create docker image
+ strategy:
+ matrix:
+ container:
+ - xenial
+ - bionic
+ - focal
+ - docurium
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ if: github.event_name == 'push'
+ - name: Download existing container
+ run: azure-pipelines/getcontainer.sh ${{ env.docker-config-path }}/${{ matrix.container }}
+ env:
+ DOCKER_REGISTRY: ${{ env.docker-registry }}
+ GITHUB_TOKEN: ${{ secrets.github_token }}
+ if: github.event_name == 'push'
+ - name: Build and publish image
+ run: |
+ docker build -t ${{ env.docker-registry-container-sha }} --build-arg BASE=${{ matrix.container.base }} -f ${{ matrix.container }} .
+ docker push ${{ env.docker-registry-container-sha }}
+ working-directory: ${{ env.docker-config-path }}
+ if: github.event_name == 'push' && env.docker-container-exists != 'true'
+
+ # Run our CI/CD builds. We build a matrix with the various build targets
+ # and their details. Then we build either in a docker container (Linux)
+ # or on the actual hosts (macOS, Windows).
+ build:
+ name: Build
+ needs: [build_containers]
+ strategy:
+ matrix:
+ platform:
+ - # Xenial, GCC, OpenSSL
+ image: xenial
+ env:
+ CC: gcc
+ CMAKE_GENERATOR: Ninja
+ CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ os: ubuntu-latest
+ - # Xenial, GCC, mbedTLS
+ image: xenial
+ env:
+ CC: gcc
+ CMAKE_GENERATOR: Ninja
+ CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ os: ubuntu-latest
+ - # Xenial, Clang, OpenSSL
+ image: xenial
+ env:
+ CC: clang
+ CMAKE_GENERATOR: Ninja
+ CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ os: ubuntu-latest
+ - # Xenial, Clang, mbedTLS
+ image: xenial
+ env:
+ CC: clang
+ CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ CMAKE_GENERATOR: Ninja
+ os: ubuntu-latest
+ - # Focal, Clang 10, mbedTLS, MemorySanitizer
+ image: focal
+ env:
+ CC: clang-10
+ CFLAGS: -fsanitize=memory -fsanitize-memory-track-origins=2 -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer
+ CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local/msan -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+ CMAKE_GENERATOR: Ninja
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+ os: ubuntu-latest
+ - # Focal, Clang 10, OpenSSL, UndefinedBehaviorSanitizer
+ image: focal
+ env:
+ CC: clang-10
+ CFLAGS: -fsanitize=undefined,nullability -fno-sanitize-recover=undefined,nullability -fsanitize-blacklist=/home/libgit2/source/script/sanitizers.supp -fno-optimize-sibling-calls -fno-omit-frame-pointer
+ CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local -DUSE_HTTPS=OpenSSL -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+ CMAKE_GENERATOR: Ninja
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
+ os: ubuntu-latest
+ - # macOS
+ os: macos-10.15
+ env:
+ CC: clang
+ CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
+ CMAKE_GENERATOR: Ninja
+ PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ setup-script: osx
+ - # Windows amd64 Visual Studio
+ os: windows-2019
+ env:
+ ARCH: amd64
+ CMAKE_GENERATOR: Visual Studio 16 2019
+ CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ - # Windows x86 Visual Studio
+ os: windows-2019
+ env:
+ ARCH: x86
+ CMAKE_GENERATOR: Visual Studio 16 2019
+ CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ - # Windows amd64 mingw
+ os: windows-2019
+ setup-script: mingw
+ env:
+ ARCH: amd64
+ CMAKE_GENERATOR: MinGW Makefiles
+ CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
+ BUILD_TEMP: D:\Temp
+ BUILD_PATH: D:\Temp\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ - # Windows x86 mingw
+ os: windows-2019
+ setup-script: mingw
+ env:
+ ARCH: x86
+ CMAKE_GENERATOR: MinGW Makefiles
+ CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
+ BUILD_TEMP: D:\Temp
+ BUILD_PATH: D:\Temp\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
+ fail-fast: false
+ env: ${{ matrix.platform.env }}
+ runs-on: ${{ matrix.platform.os }}
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Set up build environment
+ run: azure-pipelines/setup-${{ matrix.platform.setup-script }}.sh
+ shell: bash
+ if: matrix.platform.setup-script != ''
+ - name: Download container
+ run: azure-pipelines/getcontainer.sh ${{ env.docker-config-path }}/${{ matrix.platform.image }}
+ env:
+ DOCKER_REGISTRY: ${{ env.docker-registry }}
+ GITHUB_TOKEN: ${{ secrets.github_token }}
+ if: matrix.platform.image != ''
+ - name: Create container
+ run: docker build -t ${{ env.docker-registry-container-sha }} -f ${{ matrix.platform.image }} .
+ working-directory: ${{ env.docker-config-path }}
+ if: matrix.platform.image != '' && env.docker-container-exists != 'true'
+ - name: Build and test
+ run: |
+ export GITTEST_NEGOTIATE_PASSWORD="${{ secrets.GITTEST_NEGOTIATE_PASSWORD }}"
+
+ if [ -n "${{ matrix.platform.image }}" ]; then
+ docker run \
+ --rm \
+ -v "$(pwd):/home/libgit2/source" \
+ -w /home/libgit2/source \
+ -e ASAN_SYMBOLIZER_PATH \
+ -e CC \
+ -e CFLAGS \
+ -e CMAKE_GENERATOR \
+ -e CMAKE_OPTIONS \
+ -e GITTEST_NEGOTIATE_PASSWORD \
+ -e PKG_CONFIG_PATH \
+ -e SKIP_NEGOTIATE_TESTS \
+ -e SKIP_SSH_TESTS \
+ ${{ env.docker-registry-container-sha }} \
+ /bin/bash -c "mkdir build && cd build && ../azure-pipelines/build.sh && ../azure-pipelines/test.sh"
+ else
+ mkdir build && cd build
+ ../azure-pipelines/build.sh
+ ../azure-pipelines/test.sh
+ fi
+ shell: bash
+
+ # Generate documentation using docurium. We'll upload the documentation
+ # as a build artifact so that it can be reviewed as part of a pull
+ # request or in a forked build. For CI builds in the main repository's
+ # master branch, we'll push the gh-pages branch back up so that it is
+ # published to our documentation site.
+ documentation:
+ name: Generate documentation
+ needs: [build_containers]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Generate documentation
+ run: |
+ git config user.name 'Documentation Generation'
+ git config user.email 'libgit2@users.noreply.github.com'
+ git branch gh-pages origin/gh-pages
+ docker login https://${{ env.docker-registry }} -u ${{ github.actor }} -p ${{ github.token }}
+ docker run \
+ --rm \
+ -v "$(pwd):/home/libgit2/source" \
+ -w /home/libgit2/source \
+ ${{ env.docker-registry }}/${{ github.repository }}/docurium:latest \
+ cm doc api.docurium
+ git checkout gh-pages
+ zip --exclude .git/\* --exclude .gitignore --exclude .gitattributes -r api-documentation.zip .
+ - uses: actions/upload-artifact@v2
+ name: Upload artifact
+ with:
+ name: api-documentation
+ path: api-documentation.zip
+ - name: Push documentation branch
+ run: git push origin gh-pages
+ if: github.event_name == 'push' && github.repository == 'libgit2/libgit2'
-/tests/clar.suite
-/tests/clar.suite.rule
-/tests/.clarcache
-/apidocs
-/trash-*.exe
-/libgit2.pc
-/config.mak
-*.o
-*.a
-*.exe
-*.gcda
-*.gcno
-*.gcov
-.lock-wafbuild
-.waf*
build/
-build-amiga/
-tests/tmp/
-msvc/Debug/
-msvc/Release/
-*.sln
-*.suo
-*.vc*proj*
-*.sdf
-*.opensdf
-*.aps
-*.cmake
-!cmake/Modules/*.cmake
.DS_Store
*~
.*.swp
tags
-mkmf.log
-*.profdata
-*.profraw
+CMakeSettings.json
+.vs
Emeric Fermas
Emmanuel Rodriguez
Eric Myhre
+Erik Aigner
Florian Forster
Holger Weiss
Ingmar Vanhassel
# Install:
# > cmake --build . --target install
-PROJECT(libgit2 C)
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
-CMAKE_POLICY(SET CMP0015 NEW)
-IF(POLICY CMP0051)
- CMAKE_POLICY(SET CMP0051 NEW)
-ENDIF()
-IF(POLICY CMP0042)
- CMAKE_POLICY(SET CMP0042 NEW)
-ENDIF()
-IF(POLICY CMP0054)
- CMAKE_POLICY(SET CMP0054 NEW)
-ENDIF()
+CMAKE_MINIMUM_REQUIRED(VERSION 3.5.1)
+
+project(libgit2 VERSION "1.1.0" LANGUAGES C)
# Add find modules to the path
-SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${libgit2_SOURCE_DIR}/cmake/Modules/")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${libgit2_SOURCE_DIR}/cmake/")
INCLUDE(CheckLibraryExists)
INCLUDE(CheckFunctionExists)
INCLUDE(FindPkgLibraries)
INCLUDE(FindThreads)
INCLUDE(FindStatNsec)
+INCLUDE(GNUInstallDirs)
INCLUDE(IdeSplitSources)
INCLUDE(FeatureSummary)
INCLUDE(EnableWarnings)
OPTION(BUILD_CLAR "Build Tests using the Clar suite" ON)
OPTION(BUILD_EXAMPLES "Build library usage example apps" OFF)
OPTION(BUILD_FUZZERS "Build the fuzz targets" OFF)
-OPTION(TAGS "Generate tags" OFF)
-OPTION(PROFILE "Generate profiling information" OFF)
-OPTION(ENABLE_TRACE "Enables tracing support" OFF)
+OPTION(ENABLE_TRACE "Enables tracing support" ON)
OPTION(LIBGIT2_FILENAME "Name of the produced binary" OFF)
-
- SET(SHA1_BACKEND "CollisionDetection" CACHE STRING
- "Backend to use for SHA1. One of Generic, OpenSSL, Win32, CommonCrypto, mbedTLS, CollisionDetection.")
OPTION(USE_SSH "Link with libssh2 to enable SSH support" ON)
OPTION(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON)
+OPTION(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS/Generic" ON)
OPTION(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF)
OPTION(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF)
-OPTION(VALGRIND "Configure build for valgrind" OFF)
-OPTION(USE_EXT_HTTP_PARSER "Use system HTTP_Parser if available" ON)
+OPTION(USE_LEAK_CHECKER "Run tests with leak checker" OFF)
OPTION(DEBUG_POOL "Enable debug pool allocator" OFF)
OPTION(ENABLE_WERROR "Enable compilation with -Werror" OFF)
OPTION(USE_BUNDLED_ZLIB "Use the bundled version of zlib" OFF)
+ SET(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation; either system or builtin.")
OPTION(DEPRECATE_HARD "Do not include deprecated functions in the library" OFF)
+ SET(REGEX_BACKEND "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.")
+
+IF (UNIX)
+ IF (NOT USE_HTTPS)
+ OPTION(USE_NTLMCLIENT "Enable NTLM support on Unix." OFF )
+ ELSE()
+ OPTION(USE_NTLMCLIENT "Enable NTLM support on Unix." ON )
+ ENDIF()
+ENDIF()
IF (UNIX AND NOT APPLE)
OPTION(ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF)
OPTION(MSVC_CRTDBG "Enable CRTDBG memory leak reporting" OFF)
ENDIF()
-FILE(STRINGS "${libgit2_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$")
-
-STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"([0-9]+).*$" "\\1" LIBGIT2_VERSION_MAJOR "${GIT2_HEADER}")
-STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_MINOR "${GIT2_HEADER}")
-STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}")
-SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}")
-
-FILE(STRINGS "${libgit2_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION [0-9]+$")
-STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}")
-
IF (DEPRECATE_HARD)
ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD)
ENDIF()
# /Gd - explicitly set cdecl calling convention
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd")
+ IF (NOT (MSVC_VERSION LESS 1900))
+ # /guard:cf - Enable Control Flow Guard
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /guard:cf")
+ ENDIF()
+
IF (STATIC_CRT)
SET(CRT_FLAG_DEBUG "/MTd")
SET(CRT_FLAG_RELEASE "/MT")
# /NXCOMPAT - Data execution prevention (DEP)
# /LARGEADDRESSAWARE - >2GB user address space on x86
# /VERSION - Embed version information in PE header
- SET(CMAKE_EXE_LINKER_FLAGS "/DYNAMICBASE /NXCOMPAT /LARGEADDRESSAWARE /VERSION:${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}")
+ SET(CMAKE_EXE_LINKER_FLAGS "/DYNAMICBASE /NXCOMPAT /LARGEADDRESSAWARE /VERSION:${libgit2_VERSION_MAJOR}.${libgit2_VERSION_MINOR}")
+
+ IF (NOT (MSVC_VERSION LESS 1900))
+ # /GUARD:CF - Enable Control Flow Guard
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /GUARD:CF")
+ ENDIF()
# /DEBUG - Create a PDB
# /LTCG - Link time code generation (whole program optimization)
ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO=1)
ENDIF ()
- ENABLE_WARNINGS(documentation)
- DISABLE_WARNINGS(missing-field-initializers)
- ENABLE_WARNINGS(strict-aliasing)
- ENABLE_WARNINGS(strict-prototypes)
- ENABLE_WARNINGS(declaration-after-statement)
- ENABLE_WARNINGS(shift-count-overflow)
- ENABLE_WARNINGS(unused-const-variable)
- ENABLE_WARNINGS(unused-function)
- ENABLE_WARNINGS(format)
- ENABLE_WARNINGS(format-security)
- ENABLE_WARNINGS(int-conversion)
- DISABLE_WARNINGS(documentation-deprecated-sync)
-
- IF (PROFILE)
- SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}")
- SET(CMAKE_EXE_LINKER_FLAGS "-pg ${CMAKE_EXE_LINKER_FLAGS}")
- ENDIF ()
+ enable_warnings(documentation)
+ disable_warnings(documentation-deprecated-sync)
+ disable_warnings(missing-field-initializers)
+ enable_warnings(strict-aliasing)
+ enable_warnings(strict-prototypes)
+ enable_warnings(declaration-after-statement)
+ enable_warnings(shift-count-overflow)
+ enable_warnings(unused-const-variable)
+ enable_warnings(unused-function)
+ enable_warnings(int-conversion)
+
+ # MinGW uses gcc, which expects POSIX formatting for printf, but
+ # uses the Windows C library, which uses its own format specifiers.
+ # Disable format specifier warnings.
+ if(MINGW)
+ disable_warnings(format)
+ disable_warnings(format-security)
+ else()
+ enable_warnings(format)
+ enable_warnings(format-security)
+ endif()
+ENDIF()
+
+# Ensure that MinGW provides the correct header files.
+IF (WIN32 AND NOT CYGWIN)
+ ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0600)
ENDIF()
IF( NOT CMAKE_CONFIGURATION_TYPES )
ADD_SUBDIRECTORY(tests)
ENDIF ()
-IF (TAGS)
- FIND_PROGRAM(CTAGS ctags)
- IF (NOT CTAGS)
- MESSAGE(FATAL_ERROR "Could not find ctags command")
- ENDIF ()
-
- FILE(GLOB_RECURSE SRC_ALL *.[ch])
-
- ADD_CUSTOM_COMMAND(
- OUTPUT tags
- COMMAND ${CTAGS} -a ${SRC_ALL}
- DEPENDS ${SRC_ALL}
- )
- ADD_CUSTOM_TARGET(
- do_tags ALL
- DEPENDS tags
- )
-ENDIF ()
-
IF (BUILD_EXAMPLES)
ADD_SUBDIRECTORY(examples)
ENDIF ()
ADD_SUBDIRECTORY(fuzzers)
ENDIF()
-IF(CMAKE_VERSION VERSION_GREATER 3)
- FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
- FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
-ELSE()
- PRINT_ENABLED_FEATURES()
- PRINT_DISABLED_FEATURES()
-ENDIF()
+FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
+FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
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.
+
+----------------------------------------------------------------------
+
+The bundled wildmatch code is licensed under the BSD license:
+
+Copyright Rich Salz.
+All rights reserved.
+
+Redistribution and use in any form are permitted provided that the
+following restrictions are are met:
+
+1. Source distributions must retain this entire copyright notice
+ and comment.
+2. Binary distributions must include the acknowledgement ``This
+ product includes software developed by Rich Salz'' in the
+ documentation or other materials provided with the
+ distribution. This must not be represented as an endorsement
+ or promotion without specific prior written permission.
+3. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission. Credits must appear in the
+ source and documentation.
+4. Altered versions must be plainly marked as such in the source
+ and documentation and must not be misrepresented as being the
+ original software.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
| Build Status | |
| ------------ | - |
| **master** branch CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=master)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=master) |
+| **v1.0 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v1.0)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v1.0) |
| **v0.28 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.28)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.28) |
-| **v0.27 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.27)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.27) |
-| **v0.26 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.26)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.26) |
| **Nightly** builds | [![Azure Pipelines Build Status](https://libgit2.visualstudio.com/libgit2/_apis/build/status/nightly?branchName=master&label=Full+Build)](https://libgit2.visualstudio.com/libgit2/_build/latest?definitionId=9&branchName=master) [![Coverity Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/coverity?branchName=master&label=Coverity+Build)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=21?branchName=master) [![Coverity Scan Build Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) |
`libgit2` is a portable, pure C implementation of the Git core methods
* [Compiler and linker options](#compiler-and-linker-options)
* [MacOS X](#macos-x)
* [Android](#android)
+ * [MinGW](#mingw)
* [Language Bindings](#language-bindings)
* [How Can I Contribute?](#how-can-i-contribute)
* [License](#license)
2. Create the cmake build environment: `cmake ..`
3. Build libgit2: `cmake --build .`
-Trouble with these steps? Read our (troubleshooting guide)[docs/troubleshooting.md].
+Trouble with these steps? Read our [troubleshooting guide](docs/troubleshooting.md).
More detailed build guidance is available below.
Getting Help
============
-**Join us on Slack**
+**Chat with us**
-Visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up, then join
-us in `#libgit2`. If you prefer IRC, you can also point your client to our
-slack channel once you've registered.
+- via IRC: join [#libgit2](https://webchat.freenode.net/#libgit2) on Freenode
+- via Slack: visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up,
+ then join us in `#libgit2`
**Getting Help**
**Reporting Security Issues**
-In case you think to have found a security issue with libgit2, please do not
-open a public issue. Instead, you can report the issue to the private mailing
-list [security@libgit2.com](mailto:security@libgit2.com).
+Please have a look at SECURITY.md.
What It Can Do
==============
The following CMake variables are declared:
-- `BIN_INSTALL_DIR`: Where to install binaries to.
-- `LIB_INSTALL_DIR`: Where to install libraries to.
-- `INCLUDE_INSTALL_DIR`: Where to install headers to.
+- `CMAKE_INSTALL_BINDIR`: Where to install binaries to.
+- `CMAKE_INSTALL_LIBDIR`: Where to install libraries to.
+- `CMAKE_INSTALL_INCLUDEDIR`: Where to install headers to.
- `BUILD_SHARED_LIBS`: Build libgit2 as a Shared Library (defaults to ON)
- `BUILD_CLAR`: Build [Clar](https://github.com/vmg/clar)-based test suite (defaults to ON)
- `THREADSAFE`: Build libgit2 with threading support (defaults to ON)
Add `-DCMAKE_TOOLCHAIN_FILE={pathToToolchainFile}` to cmake command
when configuring.
+MinGW
+-----
+
+If you want to build the library in MinGW environment with SSH support enabled,
+you may need to pass `-DCMAKE_LIBRARY_PATH="${MINGW_PREFIX}/${MINGW_CHOST}/lib/"` flag
+to CMake when configuring. This is because CMake cannot find the Win32 libraries in
+MinGW folders by default and you might see an error message stating that CMake
+could not resolve `ws2_32` library during configuration.
+
+Another option would be to install `msys2-w32api-runtime` package before configuring.
+This package installs the Win32 libraries into `/usr/lib` folder which is by default
+recognized as the library path by CMake. Please note though that this package is meant
+for MSYS subsystem which is different from MinGW.
+
Language Bindings
==================================
* hgit2 <https://github.com/jwiegley/gitlib>
* Java
* Jagged <https://github.com/ethomson/jagged>
+* Javascript / WebAssembly ( browser and nodejs )
+ * WASM-git <https://github.com/petersalomonsen/wasm-git>
* Julia
- * LibGit2.jl <https://github.com/jakebolewski/LibGit2.jl>
+ * LibGit2.jl <https://github.com/JuliaLang/julia/tree/master/stdlib/LibGit2>
* Lua
* luagit2 <https://github.com/libgit2/luagit2>
* .NET
* Ruby
* Rugged <https://github.com/libgit2/rugged>
* Rust
- * git2-rs <https://github.com/alexcrichton/git2-rs>
+ * git2-rs <https://github.com/rust-lang/git2-rs>
* Swift
* SwiftGit2 <https://github.com/SwiftGit2/SwiftGit2>
* Vala
--- /dev/null
+# Security Policy
+
+## Supported Versions
+
+This project will always provide security fixes for the latest two released
+versions. E.g. if the latest version is v0.28.x, then we will provide security
+fixes for both v0.28.x and v0.27.y, but no later versions.
+
+## Reporting a Vulnerability
+
+In case you think to have found a security issue with libgit2, please do not
+open a public issue. Instead, you can report the issue to the private mailing
+list [security@libgit2.com](mailto:security@libgit2.com). We will acknowledge
+receipt of your message in at most three days and try to clarify further steps.
- maint/*
jobs:
-- job: linux_amd64_trusty_gcc_openssl
- displayName: 'Linux (amd64; Trusty; GCC; OpenSSL)'
+- job: linux_amd64_xenial_gcc_openssl
+ displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: azure-pipelines/docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=gcc
- CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-- job: linux_amd64_trusty_gcc_mbedtls
- displayName: 'Linux (amd64; Trusty; GCC; mbedTLS)'
+- job: linux_amd64_xenial_gcc_mbedtls
+ displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: azure-pipelines/docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=gcc
- CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-- job: linux_amd64_trusty_clang_openssl
- displayName: 'Linux (amd64; Trusty; Clang; OpenSSL)'
+- job: linux_amd64_xenial_clang_openssl
+ displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: azure-pipelines/docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=clang
- CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
-- job: linux_amd64_trusty_clang_mbedtls
- displayName: 'Linux (amd64; Trusty; Clang; mbedTLS)'
+- job: linux_amd64_xenial_clang_mbedtls
+ displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: azure-pipelines/docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=clang
- CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
+ GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: macos
- displayName: 'macOS'
+ displayName: 'macOS (amd64; 10.15)'
pool:
- vmImage: 'macOS 10.13'
+ vmImage: 'macOS-10.15'
steps:
- - bash: . '$(Build.SourcesDirectory)/ci/setup-osx.sh'
+ - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh'
displayName: Setup
- template: azure-pipelines/bash.yml
parameters:
environmentVariables:
TMPDIR: $(Agent.TempDirectory)
PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
- LEAK_CHECK: leaks
- CMAKE_OPTIONS: -G Ninja -DDEPRECATE_HARD=ON
+ CMAKE_GENERATOR: Ninja
+ CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
SKIP_SSH_TESTS: true
+ GITTEST_NEGOTIATE_PASSWORD: ${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: windows_vs_amd64
displayName: 'Windows (amd64; Visual Studio)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - template: azure-pipelines/powershell.yml
+ - template: azure-pipelines/bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013 Win64" -DDEPRECATE_HARD=ON
+ CMAKE_GENERATOR: Visual Studio 15 2017
+ CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_BUNDLED_ZLIB=ON
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
- job: windows_vs_x86
displayName: 'Windows (x86; Visual Studio)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - template: azure-pipelines/powershell.yml
+ - template: azure-pipelines/bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013" -DDEPRECATE_HARD=ON
+ CMAKE_GENERATOR: Visual Studio 15 2017
+ CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS -DUSE_BUNDLED_ZLIB=ON
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
- job: windows_mingw_amd64
displayName: 'Windows (amd64; MinGW)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1'
+ - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup
env:
TEMP: $(Agent.TempDirectory)
ARCH: amd64
- - template: azure-pipelines/powershell.yml
+ - template: azure-pipelines/bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON
- PATH: $(Agent.TempDirectory)\mingw64\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin
+ BUILD_PATH: $(Agent.TempDirectory)\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+ CMAKE_GENERATOR: MinGW Makefiles
+ CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
- job: windows_mingw_x86
displayName: 'Windows (x86; MinGW)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1'
+ - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup
workingDirectory: '$(Build.BinariesDirectory)'
env:
TEMP: $(Agent.TempDirectory)
ARCH: x86
- - template: azure-pipelines/powershell.yml
+ - template: azure-pipelines/bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON
- PATH: $(Agent.TempDirectory)\mingw32\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin
-
-- job: documentation
- displayName: 'Generate Documentation'
- pool:
- vmImage: 'Ubuntu 16.04'
- steps:
- - script: |
- git config user.name 'Documentation Generation'
- git config user.email 'noreply@libgit2.org'
- docker run --rm -v /home/vsts/work/1/s:/src -w /src libgit2/docurium:test cm doc api.docurium
- git checkout gh-pages
- cp -R * '$(Build.BinariesDirectory)'
- - task: archivefiles@2
- displayName: 'Archive Documentation'
- inputs:
- rootFolderOrFile: '$(Build.BinariesDirectory)'
- includeRootFolder: false
- archiveFile: '$(Build.ArtifactStagingDirectory)/api-documentation.zip'
- - task: publishbuildartifacts@1
- displayName: 'Upload Documentation'
- inputs:
- pathToPublish: '$(Build.ArtifactStagingDirectory)'
- artifactName: 'docs'
+ BUILD_PATH: $(Agent.TempDirectory)\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+ CMAKE_GENERATOR: MinGW Makefiles
+ CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
+ SKIP_SSH_TESTS: true
+ SKIP_NEGOTIATE_TESTS: true
# These are the steps used for building on machines with bash.
steps:
-- bash: . '$(Build.SourcesDirectory)/ci/build.sh'
+- bash: . '$(Build.SourcesDirectory)/azure-pipelines/build.sh'
displayName: Build
workingDirectory: '$(Build.BinariesDirectory)'
env: ${{ parameters.environmentVariables }}
-- bash: . '$(Build.SourcesDirectory)/ci/test.sh'
+- bash: . '$(Build.SourcesDirectory)/azure-pipelines/test.sh'
displayName: Test
workingDirectory: '$(Build.BinariesDirectory)'
env: ${{ parameters.environmentVariables }}
--- /dev/null
+#!/usr/bin/env bash
+#
+# Environment variables:
+#
+# SOURCE_DIR: Set to the directory of the libgit2 source (optional)
+# If not set, it will be derived relative to this script.
+
+set -e
+
+SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
+BUILD_DIR=$(pwd)
+BUILD_PATH=${BUILD_PATH:=$PATH}
+CMAKE=$(which cmake)
+CMAKE_GENERATOR=${CMAKE_GENERATOR:-Unix Makefiles}
+
+if [[ "$(uname -s)" == MINGW* ]]; then
+ BUILD_PATH=$(cygpath "$BUILD_PATH")
+fi
+
+indent() { sed "s/^/ /"; }
+
+echo "Source directory: ${SOURCE_DIR}"
+echo "Build directory: ${BUILD_DIR}"
+echo ""
+
+if [ "$(uname -s)" = "Darwin" ]; then
+ echo "macOS version:"
+ sw_vers | indent
+fi
+
+if [ -f "/etc/debian_version" ]; then
+ echo "Debian version:"
+ (source /etc/lsb-release && echo "${DISTRIB_DESCRIPTION}") | indent
+fi
+
+echo "Kernel version:"
+uname -a 2>&1 | indent
+
+echo "CMake version:"
+env PATH="${BUILD_PATH}" "${CMAKE}" --version 2>&1 | indent
+
+if test -n "${CC}"; then
+ echo "Compiler version:"
+ "${CC}" --version 2>&1 | indent
+fi
+echo "Environment:"
+if test -n "${CC}"; then
+ echo "CC=${CC}" | indent
+fi
+if test -n "${CFLAGS}"; then
+ echo "CFLAGS=${CFLAGS}" | indent
+fi
+echo ""
+
+echo "##############################################################################"
+echo "## Configuring build environment"
+echo "##############################################################################"
+
+echo cmake -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G \"${CMAKE_GENERATOR}\" ${CMAKE_OPTIONS} -S \"${SOURCE_DIR}\"
+env PATH="${BUILD_PATH}" "${CMAKE}" -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G "${CMAKE_GENERATOR}" ${CMAKE_OPTIONS} -S "${SOURCE_DIR}"
+
+echo ""
+echo "##############################################################################"
+echo "## Building libgit2"
+echo "##############################################################################"
+
+env PATH="${BUILD_PATH}" "${CMAKE}" --build .
--- /dev/null
+#!/bin/bash -e
+
+if test -z "$COVERITY_TOKEN"
+then
+ echo "Need to set a coverity token"
+ exit 1
+fi
+
+case $(uname -m) in
+ i?86)
+ BITS=32;;
+ amd64|x86_64)
+ BITS=64;;
+ *)
+ echo "Unsupported arch '$(uname -m)'"
+ exit 1;;
+esac
+
+SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
+SOURCE_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")"/..)
+BUILD_DIR=${SOURCE_DIR}/coverity-build
+TOOL_DIR=${BUILD_DIR}/coverity-tools
+
+# Install coverity tools
+if ! test -d "$TOOL_DIR"
+then
+ mkdir -p "$TOOL_DIR"
+ curl --silent --show-error --location --data "project=libgit2&token=$COVERITY_TOKEN" "$SCAN_TOOL" |
+ tar -xzC "$TOOL_DIR"
+ ln -s "$(find "$TOOL_DIR" -type d -name 'cov-analysis*')" "$TOOL_DIR"/cov-analysis
+fi
+
+cp "${SOURCE_DIR}/script/user_nodefs.h" "$TOOL_DIR"/cov-analysis/config/
+
+# Build libgit2 with Coverity
+mkdir -p "$BUILD_DIR"
+cd "$BUILD_DIR"
+cmake "$SOURCE_DIR"
+COVERITY_UNSUPPORTED=1 \
+ "$TOOL_DIR/cov-analysis/bin/cov-build" --dir cov-int \
+ cmake --build .
+
+# Upload results
+tar -czf libgit2.tgz cov-int
+REVISION=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD)
+HTML="$(curl \
+ --silent --show-error \
+ --write-out "\n%{http_code}" \
+ --form token="$COVERITY_TOKEN" \
+ --form email=libgit2@gmail.com \
+ --form file=@libgit2.tgz \
+ --form version="$REVISION" \
+ --form description="libgit2 build" \
+ https://scan.coverity.com/builds?project=libgit2)"
+
+# Status code is the last line
+STATUS_CODE="$(echo "$HTML" | tail -n1)"
+if test "${STATUS_CODE}" != 200 && test "${STATUS_CODE}" != 201
+then
+ echo "Received error code ${STATUS_CODE} from Coverity"
+ exit 1
+fi
- job: coverity
displayName: 'Coverity'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
+ - script: |
+ cd $(Build.SourcesDirectory)/azure-pipelines/docker
+ docker build -t libgit2/xenial --build-arg BASE=ubuntu:xenial -f xenial .
+ displayName: 'Build Docker image'
- task: Docker@0
- displayName: Build
+ displayName: Analyze
inputs:
action: 'Run an image'
- imageName: 'libgit2/trusty-openssl:latest'
+ imageName: libgit2/xenial
volumes: |
- $(Build.SourcesDirectory):/src
- $(Build.BinariesDirectory):/build
+ $(Build.SourcesDirectory):/home/libgit2/source
+ $(Build.BinariesDirectory):/home/libgit2/build
envVars: |
COVERITY_TOKEN=$(COVERITY_TOKEN)
- workDir: '/build'
- containerCommand: '/src/ci/coverity-build.sh'
+ workDir: '/home/libgit2/build'
+ containerCommand: '/home/libgit2/source/azure-pipelines/coverity.sh'
detached: false
- - task: Docker@0
- displayName: Publish
- inputs:
- action: 'Run an image'
- imageName: 'libgit2/trusty-openssl:latest'
- volumes: |
- $(Build.SourcesDirectory):/src
- $(Build.BinariesDirectory):/build
- envVars: |
- COVERITY_TOKEN=$(COVERITY_TOKEN)
- workDir: '/build'
- containerCommand: '/src/ci/coverity-publish.sh'
- detached: false
- continueOnError: true
- script: docker run --rm --privileged multiarch/qemu-user-static:register --reset
displayName: 'Register Docker QEMU'
+- task: cache@2
+ displayName: Cache Docker layers
+ inputs:
+ key: docker
+ path: /tmp/dockercache
+- script: |
+ if [ -f /tmp/dockercache/${{parameters.docker.image}}.tar ]; then docker load < /tmp/dockercache/${{parameters.docker.image}}.tar; fi
+ displayName: 'Load Docker cache'
+- script: |
+ cd $(Build.SourcesDirectory)/azure-pipelines/docker &&
+ docker build -t libgit2/${{parameters.docker.image}} --build-arg BASE=${{parameters.docker.base}} -f ${{parameters.docker.image}} . &&
+ if [ ! -d /tmp/dockercache ]; then mkdir /tmp/dockercache; fi &&
+ docker save libgit2/${{parameters.docker.image}} $(docker history -q libgit2/${{parameters.docker.image}} | grep -v '<missing>') > /tmp/dockercache/${{parameters.docker.image}}.tar
+ displayName: 'Build Docker image'
- task: docker@0
displayName: Build
inputs:
action: 'Run an image'
- imageName: ${{ parameters.imageName }}
+ imageName: libgit2/${{ parameters.docker.image }}
volumes: |
- $(Build.SourcesDirectory):/src
- $(Build.BinariesDirectory):/build
+ $(Build.SourcesDirectory):/home/libgit2/source
+ $(Build.BinariesDirectory):/home/libgit2/build
envVars: ${{ parameters.environmentVariables }}
- workDir: '/build'
- containerCommand: '/src/ci/build.sh'
+ workDir: '/home/libgit2/build'
+ containerCommand: '/home/libgit2/source/azure-pipelines/build.sh'
detached: false
- task: docker@0
displayName: Test
inputs:
action: 'Run an image'
- imageName: ${{ parameters.imageName }}
+ imageName: libgit2/${{ parameters.docker.image }}
volumes: |
- $(Build.SourcesDirectory):/src
- $(Build.BinariesDirectory):/build
+ $(Build.SourcesDirectory):/home/libgit2/source
+ $(Build.BinariesDirectory):/home/libgit2/build
envVars: ${{ parameters.environmentVariables }}
- workDir: '/build'
- containerCommand: '/src/ci/test.sh'
+ workDir: '/home/libgit2/build'
+ containerCommand: '/home/libgit2/source/azure-pipelines/test.sh'
detached: false
- task: publishtestresults@2
displayName: Publish Test Results
--- /dev/null
+FROM ubuntu:bionic AS apt
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ clang \
+ cmake \
+ curl \
+ gcc \
+ git \
+ libcurl4-openssl-dev \
+ libpcre3-dev \
+ libssh2-1-dev \
+ libssl-dev \
+ libz-dev \
+ ninja-build \
+ openjdk-8-jre-headless \
+ openssh-server \
+ openssl \
+ pkgconf \
+ python \
+ sudo \
+ valgrind \
+ && \
+ rm -rf /var/lib/apt/lists/*
+
+FROM apt AS mbedtls
+RUN cd /tmp && \
+ curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
+ tar -xz && \
+ cd mbedtls-2.16.2 && \
+ scripts/config.pl set MBEDTLS_MD4_C 1 && \
+ CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
+ ninja install && \
+ cd .. && \
+ rm -rf mbedtls-2.16.2
+
+FROM mbedtls AS configure
+COPY entrypoint.sh /usr/local/bin/entrypoint.sh
+RUN chmod a+x /usr/local/bin/entrypoint.sh
+RUN mkdir /var/run/sshd
+
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
--- /dev/null
+FROM ubuntu:bionic
+RUN apt update && apt install -y cmake pkg-config ruby ruby-dev llvm libclang-dev libssl-dev python-pygments
+RUN gem install docurium
--- /dev/null
+#!/bin/bash -e
+useradd --shell /bin/bash libgit2
+chown --recursive libgit2:libgit2 /home/libgit2
+exec sudo --preserve-env --set-home --user=libgit2 "$@"
--- /dev/null
+FROM ubuntu:focal AS apt
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ bzip2 \
+ clang-10 \
+ cmake \
+ curl \
+ gcc-10 \
+ git \
+ krb5-user \
+ libcurl4-gnutls-dev \
+ libgcrypt20-dev \
+ libkrb5-dev \
+ libpcre3-dev \
+ libssl-dev \
+ libz-dev \
+ llvm-10 \
+ make \
+ ninja-build \
+ openjdk-8-jre-headless \
+ openssh-server \
+ openssl \
+ pkgconf \
+ python \
+ sudo \
+ valgrind \
+ && \
+ rm -rf /var/lib/apt/lists/* && \
+ mkdir /usr/local/msan
+
+FROM apt AS mbedtls
+RUN cd /tmp && \
+ curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
+ tar -xz && \
+ cd mbedtls-2.16.2 && \
+ scripts/config.pl unset MBEDTLS_AESNI_C && \
+ scripts/config.pl set MBEDTLS_MD4_C 1 && \
+ mkdir build build-msan && \
+ cd build && \
+ CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
+ ninja install && \
+ cd ../build-msan && \
+ CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DCMAKE_BUILD_TYPE=MemSanDbg -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \
+ ninja install && \
+ cd .. && \
+ rm -rf mbedtls-2.16.2
+
+FROM mbedtls AS libssh2
+RUN cd /tmp && \
+ curl --insecure --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | \
+ tar -xz && \
+ cd libssh2-1.8.2 && \
+ mkdir build build-msan && \
+ cd build && \
+ CC=clang-10 CFLAGS="-fPIC" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt -DCMAKE_PREFIX_PATH=/usr/local -DCMAKE_INSTALL_PREFIX=/usr/local .. && \
+ ninja install && \
+ cd ../build-msan && \
+ CC=clang-10 CFLAGS="-fPIC -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer" LDFLAGS="-fsanitize=memory" cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=mbedTLS -DCMAKE_PREFIX_PATH=/usr/local/msan -DCMAKE_INSTALL_PREFIX=/usr/local/msan .. && \
+ ninja install && \
+ cd .. && \
+ rm -rf libssh2-1.8.2
+
+FROM libssh2 AS valgrind
+RUN cd /tmp && \
+ curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
+ tar -xj && \
+ cd valgrind-3.15.0 && \
+ CC=clang-10 ./configure && \
+ make MAKEFLAGS="-j -l$(grep -c ^processor /proc/cpuinfo)" && \
+ make install && \
+ cd .. && \
+ rm -rf valgrind-3.15.0
+
+FROM valgrind AS configure
+COPY entrypoint.sh /usr/local/bin/entrypoint.sh
+RUN chmod a+x /usr/local/bin/entrypoint.sh
+RUN mkdir /var/run/sshd
+
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
--- /dev/null
+FROM ubuntu:xenial AS apt
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ bzip2 \
+ clang \
+ cmake \
+ curl \
+ gcc \
+ git \
+ krb5-user \
+ libcurl4-gnutls-dev \
+ libgcrypt20-dev \
+ libkrb5-dev \
+ libpcre3-dev \
+ libssl-dev \
+ libz-dev \
+ make \
+ ninja-build \
+ openjdk-8-jre-headless \
+ openssh-server \
+ openssl \
+ pkgconf \
+ python \
+ sudo \
+ valgrind \
+ && \
+ rm -rf /var/lib/apt/lists/*
+
+FROM apt AS mbedtls
+RUN cd /tmp && \
+ curl --location --silent --show-error https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
+ tar -xz && \
+ cd mbedtls-2.16.2 && \
+ scripts/config.pl set MBEDTLS_MD4_C 1 && \
+ CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
+ ninja install && \
+ cd .. && \
+ rm -rf mbedtls-2.16.2
+
+FROM mbedtls AS libssh2
+RUN cd /tmp && \
+ curl --insecure --location --silent --show-error https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | \
+ tar -xz && \
+ cd libssh2-1.8.2 && \
+ CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt . && \
+ ninja install && \
+ cd .. && \
+ rm -rf libssh2-1.8.2
+
+FROM libssh2 AS valgrind
+RUN cd /tmp && \
+ curl --insecure --location --silent --show-error https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
+ tar -xj && \
+ cd valgrind-3.15.0 && \
+ ./configure && \
+ make && \
+ make install && \
+ cd .. && \
+ rm -rf valgrind-3.15.0
+
+FROM valgrind AS configure
+COPY entrypoint.sh /usr/local/bin/entrypoint.sh
+RUN chmod a+x /usr/local/bin/entrypoint.sh
+RUN mkdir /var/run/sshd
+
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
--- /dev/null
+#!/bin/bash
+
+set -e
+
+DOCKERFILE_PATH=$1
+
+if [ "${DOCKERFILE_PATH}" = "" ]; then
+ echo "usage: $0 dockerfile"
+ exit 1
+fi
+
+if [ "${DOCKER_REGISTRY}" = "" ]; then
+ echo "DOCKER_REGISTRY environment variable is unset."
+ echo "Not running inside GitHub Actions or misconfigured?"
+ exit 1
+fi
+
+DOCKER_CONTAINER="${GITHUB_REPOSITORY}/$(basename ${DOCKERFILE_PATH})"
+DOCKER_REGISTRY_CONTAINER="${DOCKER_REGISTRY}/${DOCKER_CONTAINER}"
+
+echo "::set-env name=docker-container::${DOCKER_CONTAINER}"
+echo "::set-env name=docker-registry-container::${DOCKER_REGISTRY_CONTAINER}"
+
+# Identify the last git commit that touched the Dockerfiles
+# Use this as a hash to identify the resulting docker containers
+DOCKER_SHA=$(git log -1 --pretty=format:"%h" -- "${DOCKERFILE_PATH}")
+echo "::set-env name=docker-sha::${DOCKER_SHA}"
+
+DOCKER_REGISTRY_CONTAINER_SHA="${DOCKER_REGISTRY_CONTAINER}:${DOCKER_SHA}"
+
+echo "::set-env name=docker-registry-container-sha::${DOCKER_REGISTRY_CONTAINER_SHA}"
+echo "::set-env name=docker-registry-container-latest::${DOCKER_REGISTRY_CONTAINER}:latest"
+
+exists="true"
+docker login https://${DOCKER_REGISTRY} -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN} || exists="false"
+
+if [ "${exists}" != "false" ]; then
+ docker pull ${DOCKER_REGISTRY_CONTAINER_SHA} || exists="false"
+fi
+
+if [ "${exists}" = "true" ]; then
+ echo "::set-env name=docker-container-exists::true"
+else
+ echo "::set-env name=docker-container-exists::false"
+fi
- repo: self
jobs:
-- job: linux_amd64_trusty_gcc_openssl
- displayName: 'Linux (amd64; Trusty; GCC; OpenSSL)'
+- job: linux_amd64_xenial_gcc_openssl
+ displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=gcc
- CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true
-- job: linux_amd64_trusty_gcc_mbedtls
- displayName: 'Linux (amd64; Trusty; GCC; mbedTLS)'
+- job: linux_amd64_xenial_gcc_mbedtls
+ displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=gcc
- CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true
-- job: linux_amd64_trusty_clang_openssl
- displayName: 'Linux (amd64; Trusty; Clang; OpenSSL)'
+- job: linux_amd64_xenial_clang_openssl
+ displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=clang
- CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true
-- job: linux_amd64_trusty_clang_mbedtls
- displayName: 'Linux (amd64; Trusty; Clang; mbedTLS)'
+- job: linux_amd64_xenial_clang_mbedtls
+ displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
- imageName: 'libgit2/trusty-amd64:latest'
+ docker:
+ image: xenial
+ base: ubuntu:xenial
environmentVariables: |
CC=clang
- CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true
- job: macos
- displayName: 'macOS'
+ displayName: 'macOS (amd64; 10.15)'
pool:
- vmImage: 'macOS 10.13'
+ vmImage: 'macOS-10.15'
steps:
- - bash: . '$(Build.SourcesDirectory)/ci/setup-osx.sh'
+ - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh'
displayName: Setup
- template: bash.yml
parameters:
environmentVariables:
TMPDIR: $(Agent.TempDirectory)
PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
- LEAK_CHECK: leaks
- CMAKE_OPTIONS: -G Ninja -DDEPRECATE_HARD=ON
+ CMAKE_GENERATOR: Ninja
+ CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
RUN_INVASIVE_TESTS: true
SKIP_SSH_TESTS: true
- job: windows_vs_amd64
displayName: 'Windows (amd64; Visual Studio)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - template: powershell.yml
+ - template: bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013 Win64" -DDEPRECATE_HARD=ON
+ CMAKE_GENERATOR: Visual Studio 15 2017
+ CMAKE_OPTIONS: -A x64 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS: true
+ SKIP_SSH_TESTS: true
- job: windows_vs_x86
displayName: 'Windows (x86; Visual Studio)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - template: powershell.yml
+ - template: bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013" -DDEPRECATE_HARD=ON
+ CMAKE_GENERATOR: Visual Studio 15 2017
+ CMAKE_OPTIONS: -A Win32 -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS
RUN_INVASIVE_TESTS: true
+ SKIP_SSH_TESTS: true
- job: windows_mingw_amd64
displayName: 'Windows (amd64; MinGW)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1'
+ - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup
env:
TEMP: $(Agent.TempDirectory)
ARCH: amd64
- - template: powershell.yml
+ - template: bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON
- PATH: $(Agent.TempDirectory)\mingw64\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin
+ BUILD_PATH: $(Agent.TempDirectory)\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+ CMAKE_GENERATOR: MinGW Makefiles
+ CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS: true
+ SKIP_SSH_TESTS: true
- job: windows_mingw_x86
displayName: 'Windows (x86; MinGW)'
- pool: Hosted
+ pool:
+ vmImage: 'vs2017-win2016'
steps:
- - powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1'
+ - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup
workingDirectory: '$(Build.BinariesDirectory)'
env:
TEMP: $(Agent.TempDirectory)
ARCH: x86
- - template: powershell.yml
+ - template: bash.yml
parameters:
environmentVariables:
- CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON
- PATH: $(Agent.TempDirectory)\mingw32\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin
+ BUILD_PATH: $(Agent.TempDirectory)\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
+ CMAKE_GENERATOR: MinGW Makefiles
+ CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS: true
+ SKIP_SSH_TESTS: true
- job: linux_x86_bionic_gcc_openssl
displayName: 'Linux (x86; Bionic; GCC; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
qemu: 'true'
- imageName: 'libgit2/bionic-x86:latest'
+ docker:
+ image: bionic
+ base: multiarch/ubuntu-core:x86-bionic
environmentVariables: |
CC=gcc
- CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true
- job: linux_x86_bionic_clang_openssl
displayName: 'Linux (x86; Bionic; Clang; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
qemu: 'true'
- imageName: 'libgit2/bionic-x86:latest'
+ docker:
+ image: bionic
+ base: multiarch/ubuntu-core:x86-bionic
environmentVariables: |
CC=clang
- CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
- LEAK_CHECK=valgrind
+ CMAKE_GENERATOR=Ninja
+ CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true
- job: linux_arm32_bionic_gcc_openssl
displayName: 'Linux (arm32; Bionic; GCC; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
qemu: 'true'
- imageName: 'libgit2/bionic-arm32:latest'
+ docker:
+ image: bionic
+ base: multiarch/ubuntu-core:armhf-bionic
environmentVariables: |
CC=gcc
+ CMAKE_GENERATOR=Ninja
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS=true
SKIP_PROXY_TESTS=true
- job: linux_arm64_bionic_gcc_openssl
displayName: 'Linux (arm64; Bionic; GCC; OpenSSL)'
pool:
- vmImage: 'Ubuntu 16.04'
+ vmImage: 'ubuntu-18.04'
steps:
- template: docker.yml
parameters:
qemu: 'true'
- imageName: 'libgit2/bionic-arm64:latest'
+ docker:
+ image: bionic
+ base: multiarch/ubuntu-core:arm64-bionic
environmentVariables: |
CC=gcc
+ CMAKE_GENERATOR=Ninja
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS=true
SKIP_PROXY_TESTS=true
+++ /dev/null
-# These are the steps used for building on machines with PowerShell.
-steps:
-- powershell: . '$(Build.SourcesDirectory)\ci\build.ps1'
- displayName: Build
- workingDirectory: '$(Build.BinariesDirectory)'
- env: ${{ parameters.environmentVariables }}
-- powershell: . '$(Build.SourcesDirectory)\ci\test.ps1'
- displayName: Test
- workingDirectory: '$(Build.BinariesDirectory)'
- env: ${{ parameters.environmentVariables }}
-- task: PublishTestResults@2
- displayName: Publish Test Results
- condition: succeededOrFailed()
- inputs:
- testResultsFiles: 'results_*.xml'
- searchFolder: '$(Build.BinariesDirectory)'
- mergeTestResults: true
--- /dev/null
+#!/bin/sh -e
+
+echo "##############################################################################"
+echo "## Downloading mingw"
+echo "##############################################################################"
+
+BUILD_TEMP=${BUILD_TEMP:=$TEMP}
+BUILD_TEMP=$(cygpath $BUILD_TEMP)
+
+case "$ARCH" in
+ amd64)
+ MINGW_URI="https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-x86_64-8.1.0-release-win32-seh-rt_v6-rev0.zip";;
+ x86)
+ MINGW_URI="https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";;
+esac
+
+if [ -z "$MINGW_URI" ]; then
+ echo "No URL"
+ exit 1
+fi
+
+mkdir -p "$BUILD_TEMP"
+
+curl -s -L "$MINGW_URI" -o "$BUILD_TEMP"/mingw-"$ARCH".zip
+unzip -q "$BUILD_TEMP"/mingw-"$ARCH".zip -d "$BUILD_TEMP"
--- /dev/null
+#!/bin/sh
+
+set -x
+
+brew update
+brew install pkgconfig zlib curl openssl libssh2 ninja
+
+ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib
--- /dev/null
+#!/usr/bin/env bash
+
+set -e
+
+if [ -n "$SKIP_TESTS" ]; then
+ exit 0
+fi
+
+# Windows doesn't run the NTLM tests properly (yet)
+if [[ "$(uname -s)" == MINGW* ]]; then
+ SKIP_NTLM_TESTS=1
+fi
+
+SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
+BUILD_DIR=$(pwd)
+TMPDIR=${TMPDIR:-/tmp}
+USER=${USER:-$(whoami)}
+
+SUCCESS=1
+
+cleanup() {
+ echo "Cleaning up..."
+
+ if [ ! -z "$GITDAEMON_PID" ]; then
+ echo "Stopping git daemon..."
+ kill $GITDAEMON_PID
+ fi
+
+ if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then
+ echo "Stopping SSH..."
+ kill $(cat "${SSHD_DIR}/pid")
+ fi
+
+ echo "Done."
+}
+
+run_test() {
+ if [[ "$GITTEST_FLAKY_RETRY" > 0 ]]; then
+ ATTEMPTS_REMAIN=$GITTEST_FLAKY_RETRY
+ else
+ ATTEMPTS_REMAIN=1
+ fi
+
+ FAILED=0
+ while [[ "$ATTEMPTS_REMAIN" > 0 ]]; do
+ if [ "$FAILED" -eq 1 ]; then
+ echo ""
+ echo "Re-running flaky ${1} tests..."
+ echo ""
+ fi
+
+ RETURN_CODE=0
+
+ CLAR_SUMMARY="${BUILD_DIR}/results_${1}.xml" ctest -V -R "^${1}$" || RETURN_CODE=$? && true
+
+ if [ "$RETURN_CODE" -eq 0 ]; then
+ FAILED=0
+ break
+ fi
+
+ echo "Test exited with code: $RETURN_CODE"
+ ATTEMPTS_REMAIN="$(($ATTEMPTS_REMAIN-1))"
+ FAILED=1
+ done
+
+ if [ "$FAILED" -ne 0 ]; then
+ SUCCESS=0
+ fi
+}
+
+# Configure the test environment; run them early so that we're certain
+# that they're started by the time we need them.
+
+echo "##############################################################################"
+echo "## Configuring test environment"
+echo "##############################################################################"
+
+if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
+ echo "Starting git daemon..."
+ GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX`
+ git init --bare "${GITDAEMON_DIR}/test.git"
+ git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null &
+ GITDAEMON_PID=$!
+ disown $GITDAEMON_PID
+fi
+
+if [ -z "$SKIP_PROXY_TESTS" ]; then
+ curl --location --silent --show-error https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar
+
+ echo ""
+ echo "Starting HTTP proxy (Basic)..."
+ java -jar poxyproxy.jar --address 127.0.0.1 --port 8080 --credentials foo:bar --auth-type basic --quiet &
+
+ echo ""
+ echo "Starting HTTP proxy (NTLM)..."
+ java -jar poxyproxy.jar --address 127.0.0.1 --port 8090 --credentials foo:bar --auth-type ntlm --quiet &
+fi
+
+if [ -z "$SKIP_NTLM_TESTS" ]; then
+ curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar
+
+ echo ""
+ echo "Starting HTTP server..."
+ NTLM_DIR=`mktemp -d ${TMPDIR}/ntlm.XXXXXXXX`
+ git init --bare "${NTLM_DIR}/test.git"
+ java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${NTLM_DIR}" &
+fi
+
+if [ -z "$SKIP_SSH_TESTS" ]; then
+ echo "Starting ssh daemon..."
+ HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX`
+ SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX`
+ git init --bare "${SSHD_DIR}/test.git"
+ cat >"${SSHD_DIR}/sshd_config" <<-EOF
+ Port 2222
+ ListenAddress 0.0.0.0
+ Protocol 2
+ HostKey ${SSHD_DIR}/id_rsa
+ PidFile ${SSHD_DIR}/pid
+ AuthorizedKeysFile ${HOME}/.ssh/authorized_keys
+ LogLevel DEBUG
+ RSAAuthentication yes
+ PasswordAuthentication yes
+ PubkeyAuthentication yes
+ ChallengeResponseAuthentication no
+ StrictModes no
+ # Required here as sshd will simply close connection otherwise
+ UsePAM no
+ EOF
+ ssh-keygen -t rsa -f "${SSHD_DIR}/id_rsa" -N "" -q
+ /usr/sbin/sshd -f "${SSHD_DIR}/sshd_config" -E "${SSHD_DIR}/log"
+
+ # Set up keys
+ mkdir "${HOME}/.ssh"
+ ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N "" -q
+ cat "${HOME}/.ssh/id_rsa.pub" >>"${HOME}/.ssh/authorized_keys"
+ while read algorithm key comment; do
+ echo "[localhost]:2222 $algorithm $key" >>"${HOME}/.ssh/known_hosts"
+ done <"${SSHD_DIR}/id_rsa.pub"
+
+ # Get the fingerprint for localhost and remove the colons so we can
+ # parse it as a hex number. Older versions have a different output
+ # format.
+ if [[ $(ssh -V 2>&1) == OpenSSH_6* ]]; then
+ SSH_FINGERPRINT=$(ssh-keygen -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':')
+ else
+ SSH_FINGERPRINT=$(ssh-keygen -E md5 -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 3 | cut -d : -f2- | tr -d :)
+ fi
+fi
+
+# Run the tests that do not require network connectivity.
+
+if [ -z "$SKIP_OFFLINE_TESTS" ]; then
+ echo ""
+ echo "##############################################################################"
+ echo "## Running (offline) tests"
+ echo "##############################################################################"
+
+ run_test offline
+fi
+
+if [ -n "$RUN_INVASIVE_TESTS" ]; then
+ echo ""
+ echo "Running invasive tests"
+ echo ""
+
+ export GITTEST_INVASIVE_FS_SIZE=1
+ export GITTEST_INVASIVE_MEMORY=1
+ export GITTEST_INVASIVE_SPEED=1
+ run_test invasive
+ unset GITTEST_INVASIVE_FS_SIZE
+ unset GITTEST_INVASIVE_MEMORY
+ unset GITTEST_INVASIVE_SPEED
+fi
+
+if [ -z "$SKIP_ONLINE_TESTS" ]; then
+ # Run the various online tests. The "online" test suite only includes the
+ # default online tests that do not require additional configuration. The
+ # "proxy" and "ssh" test suites require further setup.
+
+ echo ""
+ echo "##############################################################################"
+ echo "## Running (online) tests"
+ echo "##############################################################################"
+
+ export GITTEST_FLAKY_RETRY=5
+ run_test online
+ unset GITTEST_FLAKY_RETRY
+fi
+
+if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
+ echo ""
+ echo "Running gitdaemon tests"
+ echo ""
+
+ export GITTEST_REMOTE_URL="git://localhost/test.git"
+ run_test gitdaemon
+ unset GITTEST_REMOTE_URL
+fi
+
+if [ -z "$SKIP_PROXY_TESTS" ]; then
+ echo ""
+ echo "Running proxy tests (Basic authentication)"
+ echo ""
+
+ export GITTEST_REMOTE_PROXY_HOST="localhost:8080"
+ export GITTEST_REMOTE_PROXY_USER="foo"
+ export GITTEST_REMOTE_PROXY_PASS="bar"
+ run_test proxy
+ unset GITTEST_REMOTE_PROXY_HOST
+ unset GITTEST_REMOTE_PROXY_USER
+ unset GITTEST_REMOTE_PROXY_PASS
+
+ echo ""
+ echo "Running proxy tests (NTLM authentication)"
+ echo ""
+
+ export GITTEST_REMOTE_PROXY_HOST="localhost:8090"
+ export GITTEST_REMOTE_PROXY_USER="foo"
+ export GITTEST_REMOTE_PROXY_PASS="bar"
+ export GITTEST_FLAKY_RETRY=5
+ run_test proxy
+ unset GITTEST_FLAKY_RETRY
+ unset GITTEST_REMOTE_PROXY_HOST
+ unset GITTEST_REMOTE_PROXY_USER
+ unset GITTEST_REMOTE_PROXY_PASS
+fi
+
+if [ -z "$SKIP_NTLM_TESTS" ]; then
+ echo ""
+ echo "Running NTLM tests (IIS emulation)"
+ echo ""
+
+ export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git"
+ export GITTEST_REMOTE_USER="foo"
+ export GITTEST_REMOTE_PASS="baz"
+ run_test auth_clone_and_push
+ unset GITTEST_REMOTE_URL
+ unset GITTEST_REMOTE_USER
+ unset GITTEST_REMOTE_PASS
+
+ echo ""
+ echo "Running NTLM tests (Apache emulation)"
+ echo ""
+
+ export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git"
+ export GITTEST_REMOTE_USER="foo"
+ export GITTEST_REMOTE_PASS="baz"
+ run_test auth_clone_and_push
+ unset GITTEST_REMOTE_URL
+ unset GITTEST_REMOTE_USER
+ unset GITTEST_REMOTE_PASS
+fi
+
+if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then
+ echo ""
+ echo "Running SPNEGO tests"
+ echo ""
+
+ if [ "$(uname -s)" = "Darwin" ]; then
+ KINIT_FLAGS="--password-file=STDIN"
+ fi
+
+ echo $GITTEST_NEGOTIATE_PASSWORD | kinit $KINIT_FLAGS test@LIBGIT2.ORG
+ klist -5f
+
+ export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
+ export GITTEST_REMOTE_DEFAULT="true"
+ run_test auth_clone
+ unset GITTEST_REMOTE_URL
+ unset GITTEST_REMOTE_DEFAULT
+
+ echo ""
+ echo "Running SPNEGO tests (expect/continue)"
+ echo ""
+
+ export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
+ export GITTEST_REMOTE_DEFAULT="true"
+ export GITTEST_REMOTE_EXPECTCONTINUE="true"
+ run_test auth_clone
+ unset GITTEST_REMOTE_URL
+ unset GITTEST_REMOTE_DEFAULT
+ unset GITTEST_REMOTE_EXPECTCONTINUE
+
+ kdestroy -A
+fi
+
+if [ -z "$SKIP_SSH_TESTS" ]; then
+ echo ""
+ echo "Running ssh tests"
+ echo ""
+
+ export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git"
+ export GITTEST_REMOTE_USER=$USER
+ export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa"
+ export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub"
+ export GITTEST_REMOTE_SSH_PASSPHRASE=""
+ export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}"
+ run_test ssh
+ unset GITTEST_REMOTE_URL
+ unset GITTEST_REMOTE_USER
+ unset GITTEST_REMOTE_SSH_KEY
+ unset GITTEST_REMOTE_SSH_PUBKEY
+ unset GITTEST_REMOTE_SSH_PASSPHRASE
+ unset GITTEST_REMOTE_SSH_FINGERPRINT
+fi
+
+if [ -z "$SKIP_FUZZERS" ]; then
+ echo ""
+ echo "##############################################################################"
+ echo "## Running fuzzers"
+ echo "##############################################################################"
+
+ ctest -V -R 'fuzzer'
+fi
+
+cleanup
+
+if [ "$SUCCESS" -ne 1 ]; then
+ echo "Some tests failed."
+ exit 1
+fi
+
+echo "Success."
+exit 0
+++ /dev/null
-Set-StrictMode -Version Latest
-
-$ErrorActionPreference = "Stop"
-$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
-
-if ($Env:SOURCE_DIR) { $SourceDirectory = $Env:SOURCE_DIR } else { $SourceDirectory = Split-Path (Split-Path $MyInvocation.MyCommand.Path -Parent) -Parent }
-$BuildDirectory = $(Get-Location).Path
-
-Write-Host "Source directory: ${SourceDirectory}"
-Write-Host "Build directory: ${BuildDirectory}"
-Write-Host ""
-Write-Host "Operating system version:"
-Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, ServicePackMajorVersion, BuildNumber, OSArchitecture | Format-List
-Write-Host "PATH: ${Env:PATH}"
-Write-Host ""
-
-Write-Host "##############################################################################"
-Write-Host "## Configuring build environment"
-Write-Host "##############################################################################"
-
-Invoke-Expression "cmake ${SourceDirectory} -DBUILD_EXAMPLES=ON ${Env:CMAKE_OPTIONS}"
-if ($LastExitCode -ne 0) { [Environment]::Exit($LastExitCode) }
-
-Write-Host ""
-Write-Host "##############################################################################"
-Write-Host "## Building libgit2"
-Write-Host "##############################################################################"
-
-cmake --build .
-if ($LastExitCode -ne 0) { [Environment]::Exit($LastExitCode) }
+++ /dev/null
-#!/usr/bin/env bash
-#
-# Environment variables:
-#
-# SOURCE_DIR: Set to the directory of the libgit2 source (optional)
-# If not set, it will be derived relative to this script.
-
-set -e
-
-SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
-BUILD_DIR=$(pwd)
-CC=${CC:-cc}
-
-indent() { sed "s/^/ /"; }
-
-echo "Source directory: ${SOURCE_DIR}"
-echo "Build directory: ${BUILD_DIR}"
-echo ""
-
-if [ "$(uname -s)" = "Darwin" ]; then
- echo "macOS version:"
- sw_vers | indent
-fi
-
-if [ -f "/etc/debian_version" ]; then
- echo "Debian version:"
- lsb_release -a | indent
-fi
-
-echo "Kernel version:"
-uname -a 2>&1 | indent
-
-echo "CMake version:"
-cmake --version 2>&1 | indent
-echo "Compiler version:"
-$CC --version 2>&1 | indent
-echo ""
-
-echo "##############################################################################"
-echo "## Configuring build environment"
-echo "##############################################################################"
-
-echo cmake ${SOURCE_DIR} -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON ${CMAKE_OPTIONS}
-cmake ${SOURCE_DIR} -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON ${CMAKE_OPTIONS}
-
-echo ""
-echo "##############################################################################"
-echo "## Building libgit2"
-echo "##############################################################################"
-
-cmake --build .
+++ /dev/null
-#!/bin/bash
-
-set -e
-
-# Environment check
-[ -z "$COVERITY_TOKEN" ] && echo "Need to set a coverity token" && exit 1
-
-SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
-BUILD_DIR=$(pwd)
-
-case $(uname -m) in
- i?86) BITS=32 ;;
- amd64|x86_64) BITS=64 ;;
-esac
-SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
-TOOL_BASE=$(pwd)/_coverity-scan
-
-# Install coverity tools
-if [ ! -d "$TOOL_BASE" ]; then
- echo "Downloading coverity..."
- mkdir -p "$TOOL_BASE"
- pushd "$TOOL_BASE"
- wget -O coverity_tool.tgz $SCAN_TOOL \
- --post-data "project=libgit2&token=$COVERITY_TOKEN"
- tar xzf coverity_tool.tgz
- popd
- TOOL_DIR=$(find "$TOOL_BASE" -type d -name 'cov-analysis*')
- ln -s "$TOOL_DIR" "$TOOL_BASE"/cov-analysis
-fi
-
-cp "${SOURCE_DIR}/script/user_nodefs.h" "$TOOL_BASE"/cov-analysis/config/user_nodefs.h
-
-COV_BUILD="$TOOL_BASE/cov-analysis/bin/cov-build"
-
-# Configure and build
-cmake ${SOURCE_DIR}
-
-COVERITY_UNSUPPORTED=1 \
- $COV_BUILD --dir cov-int \
- cmake --build .
-
+++ /dev/null
-#!/bin/bash
-
-set -e
-
-# Results check
-[ ! -d "cov-int" ] && echo "Coverity directory not found" && exit 1
-
-# Upload results
-tar czf libgit2.tgz cov-int
-
-SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
-SHA=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD)
-
-HTML="$(curl \
- --silent \
- --write-out "\n%{http_code}" \
- --form token="$COVERITY_TOKEN" \
- --form email=libgit2@gmail.com \
- --form file=@libgit2.tgz \
- --form version="$SHA" \
- --form description="libgit2 build" \
- https://scan.coverity.com/builds?project=libgit2)"
-
-# Body is everything up to the last line
-BODY="$(echo "$HTML" | head -n-1)"
-
-# Status code is the last line
-STATUS_CODE="$(echo "$HTML" | tail -n1)"
-
-if [ "${STATUS_CODE}" != "200" -a "${STATUS_CODE}" != "201" ]; then
- echo "Received error code ${STATUS_CODE} from Coverity"
- exit 1
-fi
+++ /dev/null
-#!/bin/sh
-
-set -e
-set -x
-
-TMPDIR=${TMPDIR:-/tmp}
-
-if [ -z "$SKIP_APT" ]; then
- apt-get update
- apt-get -y install build-essential pkg-config clang cmake openssl libssl-dev libssh2-1-dev libcurl4-gnutls-dev openssh-server
-fi
-
-mkdir -p /var/run/sshd
-
-if [ "$MBEDTLS" ]; then
- MBEDTLS_DIR=${MBEDTLS_DIR:-$(mktemp -d ${TMPDIR}/mbedtls.XXXXXXXX)}
-
- git clone --depth 10 --single-branch --branch mbedtls-2.6.1 https://github.com/ARMmbed/mbedtls.git ${MBEDTLS_DIR}
- cd ${MBEDTLS_DIR}
-
- CFLAGS=-fPIC cmake -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON .
- cmake --build .
-
- if [ -z "$SKIP_MBEDTLS_INSTALL" ]; then
- make install
- fi
-fi
+++ /dev/null
-Set-StrictMode -Version Latest
-
-$ErrorActionPreference = "Stop"
-$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
-
-[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
-
-[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem");
-
-Write-Host "##############################################################################"
-Write-Host "## Downloading mingw"
-Write-Host "##############################################################################"
-
-if ($env:ARCH -eq "amd64") {
- $mingw_uri = "https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-x86_64-8.1.0-release-win32-seh-rt_v6-rev0.zip"
- $platform = "x86_64"
-} else {
- $mingw_uri = "https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip"
- $platform = "x86"
-}
-
-$wc = New-Object net.webclient
-$wc.Downloadfile($mingw_uri, "${Env:TEMP}/mingw-${Env:ARCH}.zip")
-
-[System.IO.Compression.ZipFile]::ExtractToDirectory("${Env:TEMP}/mingw-${Env:ARCH}.zip", $Env:TEMP)
+++ /dev/null
-#!/bin/sh
-
-set -x
-
-brew update
-brew install pkgconfig zlib curl openssl libssh2 ninja
-
-ln -s /Applications/Xcode.app/Contents/Developer/usr/lib/libLeaksAtExit.dylib /usr/local/lib
+++ /dev/null
-Set-StrictMode -Version Latest
-
-$ErrorActionPreference = "Stop"
-$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
-
-[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
-
-$SourceDir = Split-Path (Split-Path (Get-Variable MyInvocation).Value.MyCommand.Path)
-$BuildDir = Get-Location
-$global:Success = $true
-
-if ($Env:SKIP_TESTS) { exit }
-
-# Ask ctest what it would run if we were to invoke it directly. This lets
-# us manage the test configuration in a single place (tests/CMakeLists.txt)
-# instead of running clar here as well. But it allows us to wrap our test
-# harness with a leak checker like valgrind. Append the option to write
-# JUnit-style XML files.
-function run_test {
- $TestName = $args[0]
-
- $TestCommand = (ctest -N -V -R "^$TestName$") -join "`n"
-
- if (-Not ($TestCommand -match "(?ms).*\n^[0-9]*: Test command: ")) {
- echo "Could not find tests: $TestName"
- exit
- }
-
- $TestCommand = (ctest -N -V -R "^$TestName$") -join "`n" -replace "(?ms).*\n^[0-9]*: Test command: ","" -replace "\n.*",""
- $TestCommand += " -r${BuildDir}\results_${TestName}.xml"
-
- Invoke-Expression $TestCommand
- if ($LastExitCode -ne 0) { $global:Success = $false }
-}
-
-Write-Host "##############################################################################"
-Write-Host "## Configuring test environment"
-Write-Host "##############################################################################"
-
-if (-not $Env:SKIP_PROXY_TESTS) {
- Write-Host ""
- Write-Host "Starting HTTP proxy..."
- Invoke-WebRequest -Method GET -Uri https://github.com/ethomson/poxyproxy/releases/download/v0.4.0/poxyproxy-0.4.0.jar -OutFile poxyproxy.jar
- javaw -jar poxyproxy.jar -d --port 8080 --credentials foo:bar --quiet
-}
-
-Write-Host ""
-Write-Host "##############################################################################"
-Write-Host "## Running (offline) tests"
-Write-Host "##############################################################################"
-
-run_test offline
-
-if ($Env:RUN_INVASIVE_TESTS) {
- Write-Host ""
- Write-Host "##############################################################################"
- Write-Host "## Running (invasive) tests"
- Write-Host "##############################################################################"
-
- $Env:GITTEST_INVASIVE_FS_SIZE=1
- $Env:GITTEST_INVASIVE_MEMORY=1
- $Env:GITTEST_INVASIVE_SPEED=1
- run_test invasive
- $Env:GITTEST_INVASIVE_FS_SIZE=$null
- $Env:GITTEST_INVASIVE_MEMORY=$null
- $Env:GITTEST_INVASIVE_SPEED=$null
-}
-
-if (-not $Env:SKIP_ONLINE_TESTS) {
- Write-Host ""
- Write-Host "##############################################################################"
- Write-Host "## Running (online) tests"
- Write-Host "##############################################################################"
-
- run_test online
-}
-
-if (-not $Env:SKIP_PROXY_TESTS) {
- Write-Host ""
- Write-Host "Running proxy tests"
- Write-Host ""
-
- $Env:GITTEST_REMOTE_PROXY_HOST="localhost:8080"
- $Env:GITTEST_REMOTE_PROXY_USER="foo"
- $Env:GITTEST_REMOTE_PROXY_PASS="bar"
-
- run_test proxy
-
- $Env:GITTEST_REMOTE_PROXY_HOST=$null
- $Env:GITTEST_REMOTE_PROXY_USER=$null
- $Env:GITTEST_REMOTE_PROXY_PASS=$null
-
- taskkill /F /IM javaw.exe
-}
-
-if (-Not $global:Success) { exit 1 }
+++ /dev/null
-#!/usr/bin/env bash
-
-set -e
-
-if [ -n "$SKIP_TESTS" ]; then
- exit 0
-fi
-
-SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
-BUILD_DIR=$(pwd)
-TMPDIR=${TMPDIR:-/tmp}
-USER=${USER:-$(whoami)}
-
-SUCCESS=1
-
-VALGRIND="valgrind --leak-check=full --show-reachable=yes --error-exitcode=125 --num-callers=50 --suppressions=\"$SOURCE_DIR/libgit2_clar.supp\""
-LEAKS="MallocStackLogging=1 MallocScribble=1 MallocLogFile=/dev/null CLAR_AT_EXIT=\"leaks -quiet \$PPID\""
-
-cleanup() {
- echo "Cleaning up..."
-
- if [ ! -z "$GITDAEMON_DIR" -a -f "${GITDAEMON_DIR}/pid" ]; then
- echo "Stopping git daemon..."
- kill $(cat "${GITDAEMON_DIR}/pid")
- fi
-
- if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then
- echo "Stopping SSH..."
- kill $(cat "${SSHD_DIR}/pid")
- fi
-
- echo "Done."
-}
-
-failure() {
- echo "Test exited with code: $1"
- SUCCESS=0
-}
-
-# Ask ctest what it would run if we were to invoke it directly. This lets
-# us manage the test configuration in a single place (tests/CMakeLists.txt)
-# instead of running clar here as well. But it allows us to wrap our test
-# harness with a leak checker like valgrind. Append the option to write
-# JUnit-style XML files.
-run_test() {
- TEST_CMD=$(ctest -N -V -R "^${1}$" | sed -n 's/^[0-9]*: Test command: //p')
-
- if [ -z "$TEST_CMD" ]; then
- echo "Could not find tests: $1"
- exit 1
- fi
-
- TEST_CMD="${TEST_CMD} -r${BUILD_DIR}/results_${1}.xml"
-
- if [ "$LEAK_CHECK" = "valgrind" ]; then
- RUNNER="$VALGRIND $TEST_CMD"
- elif [ "$LEAK_CHECK" = "leaks" ]; then
- RUNNER="$LEAKS $TEST_CMD"
- else
- RUNNER="$TEST_CMD"
- fi
-
- eval $RUNNER || failure
-}
-
-# Configure the test environment; run them early so that we're certain
-# that they're started by the time we need them.
-
-echo "##############################################################################"
-echo "## Configuring test environment"
-echo "##############################################################################"
-
-if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
- echo "Starting git daemon..."
- GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX`
- git init --bare "${GITDAEMON_DIR}/test.git"
- git daemon --listen=localhost --export-all --enable=receive-pack --pid-file="${GITDAEMON_DIR}/pid" --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null &
-fi
-
-if [ -z "$SKIP_PROXY_TESTS" ]; then
- echo "Starting HTTP proxy..."
- curl -L https://github.com/ethomson/poxyproxy/releases/download/v0.4.0/poxyproxy-0.4.0.jar >poxyproxy.jar
- java -jar poxyproxy.jar -d --address 127.0.0.1 --port 8080 --credentials foo:bar --quiet &
-fi
-
-if [ -z "$SKIP_SSH_TESTS" ]; then
- echo "Starting ssh daemon..."
- HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX`
- SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX`
- git init --bare "${SSHD_DIR}/test.git"
- cat >"${SSHD_DIR}/sshd_config" <<-EOF
- Port 2222
- ListenAddress 0.0.0.0
- Protocol 2
- HostKey ${SSHD_DIR}/id_rsa
- PidFile ${SSHD_DIR}/pid
- AuthorizedKeysFile ${HOME}/.ssh/authorized_keys
- LogLevel DEBUG
- RSAAuthentication yes
- PasswordAuthentication yes
- PubkeyAuthentication yes
- ChallengeResponseAuthentication no
- StrictModes no
- # Required here as sshd will simply close connection otherwise
- UsePAM no
- EOF
- ssh-keygen -t rsa -f "${SSHD_DIR}/id_rsa" -N "" -q
- /usr/sbin/sshd -f "${SSHD_DIR}/sshd_config" -E "${SSHD_DIR}/log"
-
- # Set up keys
- mkdir "${HOME}/.ssh"
- ssh-keygen -t rsa -f "${HOME}/.ssh/id_rsa" -N "" -q
- cat "${HOME}/.ssh/id_rsa.pub" >>"${HOME}/.ssh/authorized_keys"
- while read algorithm key comment; do
- echo "[localhost]:2222 $algorithm $key" >>"${HOME}/.ssh/known_hosts"
- done <"${SSHD_DIR}/id_rsa.pub"
-
- # Get the fingerprint for localhost and remove the colons so we can
- # parse it as a hex number. Older versions have a different output
- # format.
- if [[ $(ssh -V 2>&1) == OpenSSH_6* ]]; then
- SSH_FINGERPRINT=$(ssh-keygen -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':')
- else
- SSH_FINGERPRINT=$(ssh-keygen -E md5 -F '[localhost]:2222' -f "${HOME}/.ssh/known_hosts" -l | tail -n 1 | cut -d ' ' -f 3 | cut -d : -f2- | tr -d :)
- fi
-fi
-
-# Run the tests that do not require network connectivity.
-
-if [ -z "$SKIP_OFFLINE_TESTS" ]; then
- echo ""
- echo "##############################################################################"
- echo "## Running (offline) tests"
- echo "##############################################################################"
-
- run_test offline
-fi
-
-if [ -n "$RUN_INVASIVE_TESTS" ]; then
- echo ""
- echo "Running invasive tests"
- echo ""
-
- export GITTEST_INVASIVE_FS_SIZE=1
- export GITTEST_INVASIVE_MEMORY=1
- export GITTEST_INVASIVE_SPEED=1
- run_test invasive
- unset GITTEST_INVASIVE_FS_SIZE
- unset GITTEST_INVASIVE_MEMORY
- unset GITTEST_INVASIVE_SPEED
-fi
-
-if [ -z "$SKIP_ONLINE_TESTS" ]; then
- # Run the various online tests. The "online" test suite only includes the
- # default online tests that do not require additional configuration. The
- # "proxy" and "ssh" test suites require further setup.
-
- echo ""
- echo "##############################################################################"
- echo "## Running (online) tests"
- echo "##############################################################################"
-
- run_test online
-fi
-
-if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
- echo ""
- echo "Running gitdaemon tests"
- echo ""
-
- export GITTEST_REMOTE_URL="git://localhost/test.git"
- run_test gitdaemon
- unset GITTEST_REMOTE_URL
-fi
-
-if [ -z "$SKIP_PROXY_TESTS" ]; then
- echo ""
- echo "Running proxy tests"
- echo ""
-
- export GITTEST_REMOTE_PROXY_HOST="localhost:8080"
- export GITTEST_REMOTE_PROXY_USER="foo"
- export GITTEST_REMOTE_PROXY_PASS="bar"
- run_test proxy
- unset GITTEST_REMOTE_PROXY_HOST
- unset GITTEST_REMOTE_PROXY_USER
- unset GITTEST_REMOTE_PROXY_PASS
-fi
-
-if [ -z "$SKIP_SSH_TESTS" ]; then
- echo ""
- echo "Running ssh tests"
- echo ""
-
- export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git"
- export GITTEST_REMOTE_USER=$USER
- export GITTEST_REMOTE_SSH_KEY="${HOME}/.ssh/id_rsa"
- export GITTEST_REMOTE_SSH_PUBKEY="${HOME}/.ssh/id_rsa.pub"
- export GITTEST_REMOTE_SSH_PASSPHRASE=""
- export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}"
- run_test ssh
- unset GITTEST_REMOTE_URL
- unset GITTEST_REMOTE_USER
- unset GITTEST_REMOTE_SSH_KEY
- unset GITTEST_REMOTE_SSH_PUBKEY
- unset GITTEST_REMOTE_SSH_PASSPHRASE
- unset GITTEST_REMOTE_SSH_FINGERPRINT
-fi
-
-if [ -z "$SKIP_FUZZERS" ]; then
- echo ""
- echo "##############################################################################"
- echo "## Running fuzzers"
- echo "##############################################################################"
-
- for fuzzer in fuzzers/*_fuzzer; do
- "${fuzzer}" "${SOURCE_DIR}/fuzzers/corpora/$(basename "${fuzzer%_fuzzer}")" || failure
- done
-fi
-
-cleanup
-
-if [ "$SUCCESS" -ne "1" ]; then
- echo "Some tests failed."
- exit 1
-fi
-
-echo "Success."
-exit 0
--- /dev/null
+# - Append compiler flag to CMAKE_C_FLAGS if compiler supports it
+# ADD_C_FLAG_IF_SUPPORTED(<flag>)
+# <flag> - the compiler flag to test
+# This internally calls the CHECK_C_COMPILER_FLAG macro.
+
+INCLUDE(CheckCCompilerFlag)
+
+MACRO(ADD_C_FLAG _FLAG)
+ STRING(TOUPPER ${_FLAG} UPCASE)
+ STRING(REGEX REPLACE "[-=]" "_" UPCASE_PRETTY ${UPCASE})
+ STRING(REGEX REPLACE "^_+" "" UPCASE_PRETTY ${UPCASE_PRETTY})
+ CHECK_C_COMPILER_FLAG(${_FLAG} IS_${UPCASE_PRETTY}_SUPPORTED)
+
+ IF(IS_${UPCASE_PRETTY}_SUPPORTED)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_FLAG}")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Required flag ${_FLAG} is not supported")
+ ENDIF()
+ENDMACRO()
+
+MACRO(ADD_C_FLAG_IF_SUPPORTED _FLAG)
+ STRING(TOUPPER ${_FLAG} UPCASE)
+ STRING(REGEX REPLACE "[-=]" "_" UPCASE_PRETTY ${UPCASE})
+ STRING(REGEX REPLACE "^_+" "" UPCASE_PRETTY ${UPCASE_PRETTY})
+ CHECK_C_COMPILER_FLAG(${_FLAG} IS_${UPCASE_PRETTY}_SUPPORTED)
+
+ IF(IS_${UPCASE_PRETTY}_SUPPORTED)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_FLAG}")
+ ENDIF()
+ENDMACRO()
--- /dev/null
+MACRO(ENABLE_WARNINGS flag)
+ ADD_C_FLAG_IF_SUPPORTED(-W${flag})
+ENDMACRO()
+
+MACRO(DISABLE_WARNINGS flag)
+ ADD_C_FLAG_IF_SUPPORTED(-Wno-${flag})
+ENDMACRO()
+
+IF(ENABLE_WERROR)
+ IF(MSVC)
+ ADD_COMPILE_OPTIONS(-WX)
+ ELSE()
+ ADD_C_FLAG_IF_SUPPORTED(-Werror)
+ ENDIF()
+ENDIF()
--- /dev/null
+# Find CoreFoundation.framework
+# This will define :
+#
+# COREFOUNDATION_FOUND
+# COREFOUNDATION_LIBRARIES
+# COREFOUNDATION_LDFLAGS
+#
+
+FIND_PATH(COREFOUNDATION_INCLUDE_DIR NAMES CoreFoundation.h)
+FIND_LIBRARY(COREFOUNDATION_LIBRARIES NAMES CoreFoundation)
+IF (COREFOUNDATION_INCLUDE_DIR AND COREFOUNDATION_LIBRARIES)
+ IF (NOT CoreFoundation_FIND_QUIETLY)
+ MESSAGE(STATUS "Found CoreFoundation ${COREFOUNDATION_LIBRARIES}")
+ ENDIF()
+ SET(COREFOUNDATION_FOUND TRUE)
+ SET(COREFOUNDATION_LDFLAGS "-framework CoreFoundation")
+ENDIF ()
+
+IF (CoreFoundation_FIND_REQUIRED AND NOT COREFOUNDATION_FOUND)
+ MESSAGE(FATAL_ERROR "CoreFoundation not found")
+ENDIF()
+
+MARK_AS_ADVANCED(
+ COREFOUNDATION_INCLUDE_DIR
+ COREFOUNDATION_LIBRARIES
+)
--- /dev/null
+# - Try to find GSSAPI
+# Once done this will define
+#
+# KRB5_CONFIG - Path to krb5-config
+# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI
+#
+# Read-Only variables:
+# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found
+# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Kerberos has been found
+# GSSAPI_FOUND - system has GSSAPI
+# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
+# GSSAPI_LIBRARIES - Link these to use GSSAPI
+# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
+#
+#=============================================================================
+# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+#
+
+find_path(GSSAPI_ROOT_DIR
+ NAMES
+ include/gssapi.h
+ include/gssapi/gssapi.h
+ HINTS
+ ${_GSSAPI_ROOT_HINTS}
+ PATHS
+ ${_GSSAPI_ROOT_PATHS}
+)
+mark_as_advanced(GSSAPI_ROOT_DIR)
+
+if (UNIX)
+ find_program(KRB5_CONFIG
+ NAMES
+ krb5-config
+ PATHS
+ ${GSSAPI_ROOT_DIR}/bin
+ /opt/local/bin)
+ mark_as_advanced(KRB5_CONFIG)
+
+ if (KRB5_CONFIG)
+ # Check if we have MIT KRB5
+ execute_process(
+ COMMAND
+ ${KRB5_CONFIG} --vendor
+ RESULT_VARIABLE
+ _GSSAPI_VENDOR_RESULT
+ OUTPUT_VARIABLE
+ _GSSAPI_VENDOR_STRING)
+
+ if (_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*")
+ set(GSSAPI_FLAVOR_MIT TRUE)
+ else()
+ execute_process(
+ COMMAND
+ ${KRB5_CONFIG} --libs gssapi
+ RESULT_VARIABLE
+ _GSSAPI_LIBS_RESULT
+ OUTPUT_VARIABLE
+ _GSSAPI_LIBS_STRING)
+
+ if (_GSSAPI_LIBS_STRING MATCHES ".*roken.*")
+ set(GSSAPI_FLAVOR_HEIMDAL TRUE)
+ endif()
+ endif()
+
+ # Get the include dir
+ execute_process(
+ COMMAND
+ ${KRB5_CONFIG} --cflags gssapi
+ RESULT_VARIABLE
+ _GSSAPI_INCLUDE_RESULT
+ OUTPUT_VARIABLE
+ _GSSAPI_INCLUDE_STRING)
+ string(REGEX REPLACE "(\r?\n)+$" "" _GSSAPI_INCLUDE_STRING "${_GSSAPI_INCLUDE_STRING}")
+ string(REGEX REPLACE " *-I" "" _GSSAPI_INCLUDEDIR "${_GSSAPI_INCLUDE_STRING}")
+ endif()
+
+ if (NOT GSSAPI_FLAVOR_MIT AND NOT GSSAPI_FLAVOR_HEIMDAL)
+ # Check for HEIMDAL
+ find_package(PkgConfig)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(_GSSAPI heimdal-gssapi)
+ endif (PKG_CONFIG_FOUND)
+
+ if (_GSSAPI_FOUND)
+ set(GSSAPI_FLAVOR_HEIMDAL TRUE)
+ else()
+ find_path(_GSSAPI_ROKEN
+ NAMES
+ roken.h
+ PATHS
+ ${GSSAPI_ROOT_DIR}/include
+ ${_GSSAPI_INCLUDEDIR})
+ if (_GSSAPI_ROKEN)
+ set(GSSAPI_FLAVOR_HEIMDAL TRUE)
+ endif()
+ endif ()
+ endif()
+endif (UNIX)
+
+find_path(GSSAPI_INCLUDE_DIR
+ NAMES
+ gssapi.h
+ gssapi/gssapi.h
+ PATHS
+ ${GSSAPI_ROOT_DIR}/include
+ ${_GSSAPI_INCLUDEDIR}
+)
+
+if (GSSAPI_FLAVOR_MIT)
+ find_library(GSSAPI_LIBRARY
+ NAMES
+ gssapi_krb5
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(KRB5_LIBRARY
+ NAMES
+ krb5
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(K5CRYPTO_LIBRARY
+ NAMES
+ k5crypto
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(COM_ERR_LIBRARY
+ NAMES
+ com_err
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ if (GSSAPI_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${GSSAPI_LIBRARY}
+ )
+ endif (GSSAPI_LIBRARY)
+
+ if (KRB5_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${KRB5_LIBRARY}
+ )
+ endif (KRB5_LIBRARY)
+
+ if (K5CRYPTO_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${K5CRYPTO_LIBRARY}
+ )
+ endif (K5CRYPTO_LIBRARY)
+
+ if (COM_ERR_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${COM_ERR_LIBRARY}
+ )
+ endif (COM_ERR_LIBRARY)
+endif (GSSAPI_FLAVOR_MIT)
+
+if (GSSAPI_FLAVOR_HEIMDAL)
+ find_library(GSSAPI_LIBRARY
+ NAMES
+ gssapi
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(KRB5_LIBRARY
+ NAMES
+ krb5
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(HCRYPTO_LIBRARY
+ NAMES
+ hcrypto
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(COM_ERR_LIBRARY
+ NAMES
+ com_err
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(HEIMNTLM_LIBRARY
+ NAMES
+ heimntlm
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(HX509_LIBRARY
+ NAMES
+ hx509
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(ASN1_LIBRARY
+ NAMES
+ asn1
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(WIND_LIBRARY
+ NAMES
+ wind
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ find_library(ROKEN_LIBRARY
+ NAMES
+ roken
+ PATHS
+ ${GSSAPI_ROOT_DIR}/lib
+ ${_GSSAPI_LIBDIR}
+ )
+
+ if (GSSAPI_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${GSSAPI_LIBRARY}
+ )
+ endif (GSSAPI_LIBRARY)
+
+ if (KRB5_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${KRB5_LIBRARY}
+ )
+ endif (KRB5_LIBRARY)
+
+ if (HCRYPTO_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${HCRYPTO_LIBRARY}
+ )
+ endif (HCRYPTO_LIBRARY)
+
+ if (COM_ERR_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${COM_ERR_LIBRARY}
+ )
+ endif (COM_ERR_LIBRARY)
+
+ if (HEIMNTLM_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${HEIMNTLM_LIBRARY}
+ )
+ endif (HEIMNTLM_LIBRARY)
+
+ if (HX509_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${HX509_LIBRARY}
+ )
+ endif (HX509_LIBRARY)
+
+ if (ASN1_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${ASN1_LIBRARY}
+ )
+ endif (ASN1_LIBRARY)
+
+ if (WIND_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${WIND_LIBRARY}
+ )
+ endif (WIND_LIBRARY)
+
+ if (ROKEN_LIBRARY)
+ set(GSSAPI_LIBRARIES
+ ${GSSAPI_LIBRARIES}
+ ${WIND_LIBRARY}
+ )
+ endif (ROKEN_LIBRARY)
+endif (GSSAPI_FLAVOR_HEIMDAL)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
+
+if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
+ set(GSSAPI_FOUND TRUE)
+endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
+
+# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
+mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
--- /dev/null
+# Find GSS.framework
+# This will define :
+#
+# GSSFRAMEWORK_FOUND
+# GSSFRAMEWORK_INCLUDE_DIR
+# GSSFRAMEWORK_LIBRARIES
+# GSSFRAMEWORK_LDFLAGS
+#
+
+FIND_PATH(GSSFRAMEWORK_INCLUDE_DIR NAMES GSS.h)
+FIND_LIBRARY(GSSFRAMEWORK_LIBRARIES NAMES GSS)
+IF (GSSFRAMEWORK_INCLUDE_DIR AND GSSFRAMEWORK_LIBRARIES)
+ IF (NOT CoreFoundation_FIND_QUIETLY)
+ MESSAGE(STATUS "Found GSS.framework ${GSSFRAMEWORK_LIBRARIES}")
+ ENDIF()
+ SET(GSSFRAMEWORK_FOUND TRUE)
+ SET(GSSFRAMEWORK_LDFLAGS "-framework GSS")
+ENDIF ()
+
+IF (GSS_FIND_REQUIRED AND NOT GSSFRAMEWORK_FOUND)
+ MESSAGE(FATAL_ERROR "CoreFoundation not found")
+ENDIF()
+
+MARK_AS_ADVANCED(
+ GSSFRAMEWORK_INCLUDE_DIR
+ GSSFRAMEWORK_LIBRARIES
+ GSSFRAMEWORK_LDFLAGS
+)
--- /dev/null
+# - Try to find http-parser
+#
+# Defines the following variables:
+#
+# HTTP_PARSER_FOUND - system has http-parser
+# HTTP_PARSER_INCLUDE_DIR - the http-parser include directory
+# HTTP_PARSER_LIBRARIES - Link these to use http-parser
+# HTTP_PARSER_VERSION_MAJOR - major version
+# HTTP_PARSER_VERSION_MINOR - minor version
+# HTTP_PARSER_VERSION_STRING - the version of http-parser found
+
+# Find the header and library
+FIND_PATH(HTTP_PARSER_INCLUDE_DIR NAMES http_parser.h)
+FIND_LIBRARY(HTTP_PARSER_LIBRARY NAMES http_parser libhttp_parser)
+
+# Found the header, read version
+if (HTTP_PARSER_INCLUDE_DIR AND EXISTS "${HTTP_PARSER_INCLUDE_DIR}/http_parser.h")
+ FILE(READ "${HTTP_PARSER_INCLUDE_DIR}/http_parser.h" HTTP_PARSER_H)
+ IF (HTTP_PARSER_H)
+ STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MAJOR[\t ]+([0-9]+).*" "\\1" HTTP_PARSER_VERSION_MAJOR "${HTTP_PARSER_H}")
+ STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MINOR[\t ]+([0-9]+).*" "\\1" HTTP_PARSER_VERSION_MINOR "${HTTP_PARSER_H}")
+ SET(HTTP_PARSER_VERSION_STRING "${HTTP_PARSER_VERSION_MAJOR}.${HTTP_PARSER_VERSION_MINOR}")
+ ENDIF()
+ UNSET(HTTP_PARSER_H)
+ENDIF()
+
+# Handle the QUIETLY and REQUIRED arguments and set HTTP_PARSER_FOUND
+# to TRUE if all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTTP_Parser REQUIRED_VARS HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY)
+
+# Hide advanced variables
+MARK_AS_ADVANCED(HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY)
+
+# Set standard variables
+IF (HTTP_PARSER_FOUND)
+ SET(HTTP_PARSER_LIBRARIES ${HTTP_PARSER_LIBRARY})
+ set(HTTP_PARSER_INCLUDE_DIRS ${HTTP_PARSER_INCLUDE_DIR})
+ENDIF()
--- /dev/null
+# - Try to find Iconv
+# Once done this will define
+#
+# ICONV_FOUND - system has Iconv
+# ICONV_INCLUDE_DIR - the Iconv include directory
+# ICONV_LIBRARIES - Link these to use Iconv
+#
+
+IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ # Already in cache, be silent
+ SET(ICONV_FIND_QUIETLY TRUE)
+ENDIF()
+
+FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
+CHECK_FUNCTION_EXISTS(iconv_open libc_has_iconv)
+FIND_LIBRARY(iconv_lib NAMES iconv libiconv libiconv-2 c)
+
+IF(ICONV_INCLUDE_DIR AND libc_has_iconv)
+ SET(ICONV_FOUND TRUE)
+ SET(ICONV_LIBRARIES "")
+ IF(NOT ICONV_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Iconv: provided by libc")
+ ENDIF(NOT ICONV_FIND_QUIETLY)
+ELSEIF(ICONV_INCLUDE_DIR AND iconv_lib)
+ SET(ICONV_FOUND TRUE)
+ # split iconv into -L and -l linker options, so we can
+ # set them for pkg-config
+ GET_FILENAME_COMPONENT(iconv_path ${iconv_lib} PATH)
+ GET_FILENAME_COMPONENT(iconv_name ${iconv_lib} NAME_WE)
+ STRING(REGEX REPLACE "^lib" "" iconv_name ${iconv_name})
+ SET(ICONV_LIBRARIES "-L${iconv_path} -l${iconv_name}")
+
+ IF(NOT ICONV_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
+ ENDIF(NOT ICONV_FIND_QUIETLY)
+ELSE()
+ IF(Iconv_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find Iconv")
+ ENDIF(Iconv_FIND_REQUIRED)
+ENDIF()
+
+MARK_AS_ADVANCED(
+ ICONV_INCLUDE_DIR
+ ICONV_LIBRARIES
+)
--- /dev/null
+# Copyright (C) 2007-2009 LuaDist.
+# Created by Peter Kapec <kapecp@gmail.com>
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Note:
+# Searching headers and libraries is very simple and is NOT as powerful as scripts
+# distributed with CMake, because LuaDist defines directories to search for.
+# Everyone is encouraged to contact the author with improvements. Maybe this file
+# becomes part of CMake distribution sometimes.
+
+# - Find pcre
+# Find the native PCRE headers and libraries.
+#
+# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
+# PCRE_LIBRARIES - List of libraries when using pcre.
+# PCRE_FOUND - True if pcre found.
+
+# Look for the header file.
+FIND_PATH(PCRE_INCLUDE_DIR NAMES pcreposix.h)
+
+# Look for the library.
+FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
+FIND_LIBRARY(PCRE_POSIX_LIBRARY NAMES pcreposix)
+
+# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_POSIX_LIBRARY PCRE_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+IF(PCRE_FOUND)
+ SET(PCRE_LIBRARIES ${PCRE_LIBRARY} ${PCRE_POSIX_LIBRARY})
+ SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
+ELSE(PCRE_FOUND)
+ SET(PCRE_LIBRARIES)
+ SET(PCRE_INCLUDE_DIRS)
+ENDIF(PCRE_FOUND)
+
+MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)
--- /dev/null
+# Copyright (C) 2007-2009 LuaDist.
+# Created by Peter Kapec <kapecp@gmail.com>
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Note:
+# Searching headers and libraries is very simple and is NOT as powerful as scripts
+# distributed with CMake, because LuaDist defines directories to search for.
+# Everyone is encouraged to contact the author with improvements. Maybe this file
+# becomes part of CMake distribution sometimes.
+
+# - Find pcre
+# Find the native PCRE2 headers and libraries.
+#
+# PCRE2_INCLUDE_DIRS - where to find pcre.h, etc.
+# PCRE2_LIBRARIES - List of libraries when using pcre.
+# PCRE2_FOUND - True if pcre found.
+
+# Look for the header file.
+FIND_PATH(PCRE2_INCLUDE_DIR NAMES pcre2posix.h)
+
+# Look for the library.
+FIND_LIBRARY(PCRE2_LIBRARY NAMES pcre2-8)
+
+# Handle the QUIETLY and REQUIRED arguments and set PCRE2_FOUND to TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE2 DEFAULT_MSG PCRE2_LIBRARY PCRE2_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+IF(PCRE2_FOUND)
+ SET(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
+ SET(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
+ELSE(PCRE2_FOUND)
+ SET(PCRE2_LIBRARIES)
+ SET(PCRE2_INCLUDE_DIRS)
+ENDIF(PCRE2_FOUND)
+
+MARK_AS_ADVANCED(PCRE2_INCLUDE_DIRS PCRE2_LIBRARIES)
--- /dev/null
+INCLUDE(FindPkgConfig)
+
+# This function will find and set up a pkg-config based module.
+# If a pc-file was found, it will resolve library paths to
+# absolute paths. Furthermore, the function will automatically
+# fall back to use static libraries in case no dynamic libraries
+# were found.
+FUNCTION(FIND_PKGLIBRARIES prefix package)
+ PKG_CHECK_MODULES(${prefix} ${package})
+ IF(NOT ${prefix}_FOUND)
+ RETURN()
+ ENDIF()
+
+ FOREACH(LIBRARY ${${prefix}_LIBRARIES})
+ FIND_LIBRARY(${LIBRARY}_RESOLVED ${LIBRARY} PATHS ${${prefix}_LIBRARY_DIRS})
+ IF(${${LIBRARY}_RESOLVED} STREQUAL "${LIBRARY}_RESOLVED-NOTFOUND")
+ MESSAGE(FATAL_ERROR "could not resolve ${LIBRARY}")
+ ENDIF()
+ LIST(APPEND RESOLVED_LIBRARIES ${${LIBRARY}_RESOLVED})
+ ENDFOREACH(LIBRARY)
+
+ SET(${prefix}_FOUND 1 PARENT_SCOPE)
+ SET(${prefix}_LIBRARIES ${RESOLVED_LIBRARIES} PARENT_SCOPE)
+ SET(${prefix}_INCLUDE_DIRS ${${prefix}_INCLUDE_DIRS} PARENT_SCOPE)
+ SET(${prefix}_LDFLAGS ${${prefix}_LDFLAGS} PARENT_SCOPE)
+
+ MESSAGE(STATUS " Resolved libraries: ${RESOLVED_LIBRARIES}")
+ENDFUNCTION()
--- /dev/null
+# Find Security.framework
+# This will define :
+#
+# SECURITY_FOUND
+# SECURITY_LIBRARIES
+# SECURITY_LDFLAGS
+# SECURITY_HAS_SSLCREATECONTEXT
+#
+
+FIND_PATH(SECURITY_INCLUDE_DIR NAMES Security/Security.h)
+FIND_LIBRARY(SECURITY_LIBRARIES NAMES Security)
+IF (SECURITY_INCLUDE_DIR AND SECURITY_LIBRARIES)
+ IF (NOT Security_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Security ${SECURITY_LIBRARIES}")
+ ENDIF()
+ SET(SECURITY_FOUND TRUE)
+ SET(SECURITY_LDFLAGS "-framework Security")
+ CHECK_LIBRARY_EXISTS("${SECURITY_LIBRARIES}" SSLCreateContext "Security/SecureTransport.h" SECURITY_HAS_SSLCREATECONTEXT)
+ENDIF ()
+
+IF (Security_FIND_REQUIRED AND NOT SECURITY_FOUND)
+ MESSAGE(FATAL_ERROR "Security not found")
+ENDIF()
+
+MARK_AS_ADVANCED(
+ SECURITY_INCLUDE_DIR
+ SECURITY_LIBRARIES
+)
--- /dev/null
+INCLUDE(FeatureSummary)
+
+CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtim "sys/types.h;sys/stat.h"
+ HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C)
+CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtimespec "sys/types.h;sys/stat.h"
+ HAVE_STRUCT_STAT_ST_MTIMESPEC LANGUAGE C)
+CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtime_nsec sys/stat.h
+ HAVE_STRUCT_STAT_MTIME_NSEC LANGUAGE C)
+
+IF (HAVE_STRUCT_STAT_ST_MTIM)
+ CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtim.tv_nsec sys/stat.h
+ HAVE_STRUCT_STAT_NSEC LANGUAGE C)
+ELSEIF (HAVE_STRUCT_STAT_ST_MTIMESPEC)
+ CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec sys/stat.h
+ HAVE_STRUCT_STAT_NSEC LANGUAGE C)
+ELSE ()
+ SET( HAVE_STRUCT_STAT_NSEC ON )
+ENDIF()
+
+IF (HAVE_STRUCT_STAT_NSEC OR WIN32)
+ OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" ON )
+ELSE()
+ SET(USE_NSEC OFF)
+ENDIF()
+
+ADD_FEATURE_INFO(nanoseconds USE_NSEC "whether to use sub-second file mtimes and ctimes")
--- /dev/null
+# - Try to find mbedTLS
+# Once done this will define
+#
+# Read-Only variables
+# MBEDTLS_FOUND - system has mbedTLS
+# MBEDTLS_INCLUDE_DIR - the mbedTLS include directory
+# MBEDTLS_LIBRARY_DIR - the mbedTLS library directory
+# MBEDTLS_LIBRARIES - Link these to use mbedTLS
+# MBEDTLS_LIBRARY - path to mbedTLS library
+# MBEDX509_LIBRARY - path to mbedTLS X.509 library
+# MBEDCRYPTO_LIBRARY - path to mbedTLS Crypto library
+#
+# Hint
+# MBEDTLS_ROOT_DIR can be pointed to a local mbedTLS installation.
+
+SET(_MBEDTLS_ROOT_HINTS
+ ${MBEDTLS_ROOT_DIR}
+ ENV MBEDTLS_ROOT_DIR
+)
+
+SET(_MBEDTLS_ROOT_HINTS_AND_PATHS
+ HINTS ${_MBEDTLS_ROOT_HINTS}
+ PATHS ${_MBEDTLS_ROOT_PATHS}
+)
+
+FIND_PATH(MBEDTLS_INCLUDE_DIR
+ NAMES mbedtls/version.h
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES include
+)
+
+IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES)
+ # Already in cache, be silent
+ SET(MBEDTLS_FIND_QUIETLY TRUE)
+ENDIF()
+
+FIND_LIBRARY(MBEDTLS_LIBRARY
+ NAMES mbedtls libmbedtls
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES library
+)
+FIND_LIBRARY(MBEDX509_LIBRARY
+ NAMES mbedx509 libmbedx509
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES library
+)
+FIND_LIBRARY(MBEDCRYPTO_LIBRARY
+ NAMES mbedcrypto libmbedcrypto
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES library
+)
+
+IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY)
+ SET(MBEDTLS_FOUND TRUE)
+ENDIF()
+
+IF(MBEDTLS_FOUND)
+ # split mbedTLS into -L and -l linker options, so we can set them for pkg-config
+ GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_DIR ${MBEDTLS_LIBRARY} PATH)
+ GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY} NAME_WE)
+ GET_FILENAME_COMPONENT(MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY} NAME_WE)
+ GET_FILENAME_COMPONENT(MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY} NAME_WE)
+ STRING(REGEX REPLACE "^lib" "" MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY_FILE})
+ STRING(REGEX REPLACE "^lib" "" MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY_FILE})
+ STRING(REGEX REPLACE "^lib" "" MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY_FILE})
+ SET(MBEDTLS_LIBRARIES "-L${MBEDTLS_LIBRARY_DIR} -l${MBEDTLS_LIBRARY_FILE} -l${MBEDX509_LIBRARY_FILE} -l${MBEDCRYPTO_LIBRARY_FILE}")
+
+ IF(NOT MBEDTLS_FIND_QUIETLY)
+ MESSAGE(STATUS "Found mbedTLS:")
+ FILE(READ ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h MBEDTLSCONTENT)
+ STRING(REGEX MATCH "MBEDTLS_VERSION_STRING +\"[0-9|.]+\"" MBEDTLSMATCH ${MBEDTLSCONTENT})
+ IF (MBEDTLSMATCH)
+ STRING(REGEX REPLACE "MBEDTLS_VERSION_STRING +\"([0-9|.]+)\"" "\\1" MBEDTLS_VERSION ${MBEDTLSMATCH})
+ MESSAGE(STATUS " version ${MBEDTLS_VERSION}")
+ ENDIF(MBEDTLSMATCH)
+ MESSAGE(STATUS " TLS: ${MBEDTLS_LIBRARY}")
+ MESSAGE(STATUS " X509: ${MBEDX509_LIBRARY}")
+ MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
+ ENDIF(NOT MBEDTLS_FIND_QUIETLY)
+ELSE(MBEDTLS_FOUND)
+ IF(MBEDTLS_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find mbedTLS")
+ ENDIF(MBEDTLS_FIND_REQUIRED)
+ENDIF(MBEDTLS_FOUND)
+
+MARK_AS_ADVANCED(
+ MBEDTLS_INCLUDE_DIR
+ MBEDTLS_LIBRARY_DIR
+ MBEDTLS_LIBRARIES
+ MBEDTLS_LIBRARY
+ MBEDX509_LIBRARY
+ MBEDCRYPTO_LIBRARY
+)
--- /dev/null
+# This function splits the sources files up into their appropriate
+# subdirectories. This is especially useful for IDEs like Xcode and
+# Visual Studio, so that you can navigate into the libgit2_clar project,
+# and see the folders within the tests folder (instead of just seeing all
+# source and tests in a single folder.)
+FUNCTION(IDE_SPLIT_SOURCES target)
+ IF(MSVC_IDE OR CMAKE_GENERATOR STREQUAL Xcode)
+ GET_TARGET_PROPERTY(sources ${target} SOURCES)
+ FOREACH(source ${sources})
+ IF(source MATCHES ".*/")
+ STRING(REPLACE ${libgit2_SOURCE_DIR}/ "" rel ${source})
+ IF(rel)
+ STRING(REGEX REPLACE "/([^/]*)$" "" rel ${rel})
+ IF(rel)
+ STRING(REPLACE "/" "\\\\" rel ${rel})
+ SOURCE_GROUP(${rel} FILES ${source})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ ENDFOREACH()
+ ENDIF()
+ENDFUNCTION()
+++ /dev/null
-# - Append compiler flag to CMAKE_C_FLAGS if compiler supports it
-# ADD_C_FLAG_IF_SUPPORTED(<flag>)
-# <flag> - the compiler flag to test
-# This internally calls the CHECK_C_COMPILER_FLAG macro.
-
-INCLUDE(CheckCCompilerFlag)
-
-MACRO(ADD_C_FLAG _FLAG)
- STRING(TOUPPER ${_FLAG} UPCASE)
- STRING(REGEX REPLACE "[-=]" "_" UPCASE_PRETTY ${UPCASE})
- STRING(REGEX REPLACE "^_+" "" UPCASE_PRETTY ${UPCASE_PRETTY})
- CHECK_C_COMPILER_FLAG(${_FLAG} IS_${UPCASE_PRETTY}_SUPPORTED)
-
- IF(IS_${UPCASE_PRETTY}_SUPPORTED)
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_FLAG}")
- ELSE()
- MESSAGE(FATAL_ERROR "Required flag ${_FLAG} is not supported")
- ENDIF()
-ENDMACRO()
-
-MACRO(ADD_C_FLAG_IF_SUPPORTED _FLAG)
- STRING(TOUPPER ${_FLAG} UPCASE)
- STRING(REGEX REPLACE "[-=]" "_" UPCASE_PRETTY ${UPCASE})
- STRING(REGEX REPLACE "^_+" "" UPCASE_PRETTY ${UPCASE_PRETTY})
- CHECK_C_COMPILER_FLAG(${_FLAG} IS_${UPCASE_PRETTY}_SUPPORTED)
-
- IF(IS_${UPCASE_PRETTY}_SUPPORTED)
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_FLAG}")
- ENDIF()
-ENDMACRO()
+++ /dev/null
-@CHECK_PROTOTYPE_DEFINITION_HEADER@
-
-static void cmakeRequireSymbol(int dummy, ...) {
- (void) dummy;
-}
-
-static void checkSymbol(void) {
-#ifndef @CHECK_PROTOTYPE_DEFINITION_SYMBOL@
- cmakeRequireSymbol(0, &@CHECK_PROTOTYPE_DEFINITION_SYMBOL@);
-#endif
-}
-
-@CHECK_PROTOTYPE_DEFINITION_PROTO@ {
- return @CHECK_PROTOTYPE_DEFINITION_RETURN@;
-}
-
-#ifdef __CLASSIC_C__
-int main() {
- int ac;
- char*av[];
-#else
-int main(int ac, char *av[]) {
-#endif
- checkSymbol();
- if (ac > 1000) {
- return *av[0];
- }
- return 0;
-}
+++ /dev/null
-# - Check if the protoype we expect is correct.
-# check_prototype_definition(FUNCTION PROTOTYPE RETURN HEADER VARIABLE)
-# FUNCTION - The name of the function (used to check if prototype exists)
-# PROTOTYPE- The prototype to check.
-# RETURN - The return value of the function.
-# HEADER - The header files required.
-# VARIABLE - The variable to store the result.
-# Example:
-# check_prototype_definition(getpwent_r
-# "struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)"
-# "NULL"
-# "unistd.h;pwd.h"
-# SOLARIS_GETPWENT_R)
-# The following variables may be set before calling this macro to
-# modify the way the check is run:
-#
-# CMAKE_REQUIRED_FLAGS = string of compile command line flags
-# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
-# CMAKE_REQUIRED_INCLUDES = list of include directories
-# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-#=============================================================================
-# Copyright 2005-2009 Kitware, Inc.
-# Copyright 2010-2011 Andreas Schneider <asn@cryptomilk.org>
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-# License text for the above reference.)
-#
-
-get_filename_component(__check_proto_def_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
-
-function(CHECK_PROTOTYPE_DEFINITION _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE)
-
- if ("${_VARIABLE}" MATCHES "^${_VARIABLE}$")
- set(CHECK_PROTOTYPE_DEFINITION_CONTENT "/* */\n")
-
- set(CHECK_PROTOTYPE_DEFINITION_FLAGS ${CMAKE_REQUIRED_FLAGS})
- if (CMAKE_REQUIRED_LIBRARIES)
- set(CHECK_PROTOTYPE_DEFINITION_LIBS
- "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
- else(CMAKE_REQUIRED_LIBRARIES)
- set(CHECK_PROTOTYPE_DEFINITION_LIBS)
- endif(CMAKE_REQUIRED_LIBRARIES)
- if (CMAKE_REQUIRED_INCLUDES)
- set(CMAKE_SYMBOL_EXISTS_INCLUDES
- "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
- else(CMAKE_REQUIRED_INCLUDES)
- set(CMAKE_SYMBOL_EXISTS_INCLUDES)
- endif(CMAKE_REQUIRED_INCLUDES)
-
- foreach(_FILE ${_HEADER})
- set(CHECK_PROTOTYPE_DEFINITION_HEADER
- "${CHECK_PROTOTYPE_DEFINITION_HEADER}#include <${_FILE}>\n")
- endforeach(_FILE)
-
- set(CHECK_PROTOTYPE_DEFINITION_SYMBOL ${_FUNCTION})
- set(CHECK_PROTOTYPE_DEFINITION_PROTO ${_PROTOTYPE})
- set(CHECK_PROTOTYPE_DEFINITION_RETURN ${_RETURN})
-
- configure_file("${__check_proto_def_dir}/CheckPrototypeDefinition.c.in"
- "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c" @ONLY)
-
- file(READ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c _SOURCE)
-
- try_compile(${_VARIABLE}
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CHECK_PROTOTYPE_DEFINITION_FLAGS}
- "${CHECK_PROTOTYPE_DEFINITION_LIBS}"
- "${CMAKE_SYMBOL_EXISTS_INCLUDES}"
- OUTPUT_VARIABLE OUTPUT)
-
- if (${_VARIABLE})
- set(${_VARIABLE} 1 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
- message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - True")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} passed with the following output:\n"
- "${OUTPUT}\n\n")
- else (${_VARIABLE})
- message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - False")
- set(${_VARIABLE} 0 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}")
- file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} failed with the following output:\n"
- "${OUTPUT}\n\n${_SOURCE}\n\n")
- endif (${_VARIABLE})
- endif("${_VARIABLE}" MATCHES "^${_VARIABLE}$")
-
-endfunction(CHECK_PROTOTYPE_DEFINITION)
+++ /dev/null
-MACRO(ENABLE_WARNINGS flag)
- ADD_C_FLAG_IF_SUPPORTED(-W${flag})
-ENDMACRO()
-
-MACRO(DISABLE_WARNINGS flag)
- ADD_C_FLAG_IF_SUPPORTED(-Wno-${flag})
-ENDMACRO()
-
-IF(ENABLE_WERROR)
- ADD_C_FLAG_IF_SUPPORTED(-Werror)
-ENDIF()
+++ /dev/null
-# Find CoreFoundation.framework
-# This will define :
-#
-# COREFOUNDATION_FOUND
-# COREFOUNDATION_LIBRARIES
-# COREFOUNDATION_LDFLAGS
-#
-
-FIND_PATH(COREFOUNDATION_INCLUDE_DIR NAMES CoreFoundation.h)
-FIND_LIBRARY(COREFOUNDATION_LIBRARIES NAMES CoreFoundation)
-IF (COREFOUNDATION_INCLUDE_DIR AND COREFOUNDATION_LIBRARIES)
- IF (NOT CoreFoundation_FIND_QUIETLY)
- MESSAGE("-- Found CoreFoundation ${COREFOUNDATION_LIBRARIES}")
- ENDIF()
- SET(COREFOUNDATION_FOUND TRUE)
- SET(COREFOUNDATION_LDFLAGS "-framework CoreFoundation")
-ENDIF ()
-
-IF (CoreFoundation_FIND_REQUIRED AND NOT COREFOUNDATION_FOUND)
- MESSAGE(FATAL "-- CoreFoundation not found")
-ENDIF()
-
-MARK_AS_ADVANCED(
- COREFOUNDATION_INCLUDE_DIR
- COREFOUNDATION_LIBRARIES
-)
+++ /dev/null
-# - Try to find GSSAPI
-# Once done this will define
-#
-# KRB5_CONFIG - Path to krb5-config
-# GSSAPI_ROOT_DIR - Set this variable to the root installation of GSSAPI
-#
-# Read-Only variables:
-# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found
-# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found
-# GSSAPI_FOUND - system has GSSAPI
-# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
-# GSSAPI_LIBRARIES - Link these to use GSSAPI
-# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
-#
-#=============================================================================
-# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-#
-
-find_path(GSSAPI_ROOT_DIR
- NAMES
- include/gssapi.h
- include/gssapi/gssapi.h
- HINTS
- ${_GSSAPI_ROOT_HINTS}
- PATHS
- ${_GSSAPI_ROOT_PATHS}
-)
-mark_as_advanced(GSSAPI_ROOT_DIR)
-
-if (UNIX)
- find_program(KRB5_CONFIG
- NAMES
- krb5-config
- PATHS
- ${GSSAPI_ROOT_DIR}/bin
- /opt/local/bin)
- mark_as_advanced(KRB5_CONFIG)
-
- if (KRB5_CONFIG)
- # Check if we have MIT KRB5
- execute_process(
- COMMAND
- ${KRB5_CONFIG} --vendor
- RESULT_VARIABLE
- _GSSAPI_VENDOR_RESULT
- OUTPUT_VARIABLE
- _GSSAPI_VENDOR_STRING)
-
- if (_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*")
- set(GSSAPI_FLAVOR_MIT TRUE)
- else()
- execute_process(
- COMMAND
- ${KRB5_CONFIG} --libs gssapi
- RESULT_VARIABLE
- _GSSAPI_LIBS_RESULT
- OUTPUT_VARIABLE
- _GSSAPI_LIBS_STRING)
-
- if (_GSSAPI_LIBS_STRING MATCHES ".*roken.*")
- set(GSSAPI_FLAVOR_HEIMDAL TRUE)
- endif()
- endif()
-
- # Get the include dir
- execute_process(
- COMMAND
- ${KRB5_CONFIG} --cflags gssapi
- RESULT_VARIABLE
- _GSSAPI_INCLUDE_RESULT
- OUTPUT_VARIABLE
- _GSSAPI_INCLUDE_STRING)
- string(REGEX REPLACE "(\r?\n)+$" "" _GSSAPI_INCLUDE_STRING "${_GSSAPI_INCLUDE_STRING}")
- string(REGEX REPLACE " *-I" "" _GSSAPI_INCLUDEDIR "${_GSSAPI_INCLUDE_STRING}")
- endif()
-
- if (NOT GSSAPI_FLAVOR_MIT AND NOT GSSAPI_FLAVOR_HEIMDAL)
- # Check for HEIMDAL
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(_GSSAPI heimdal-gssapi)
- endif (PKG_CONFIG_FOUND)
-
- if (_GSSAPI_FOUND)
- set(GSSAPI_FLAVOR_HEIMDAL TRUE)
- else()
- find_path(_GSSAPI_ROKEN
- NAMES
- roken.h
- PATHS
- ${GSSAPI_ROOT_DIR}/include
- ${_GSSAPI_INCLUDEDIR})
- if (_GSSAPI_ROKEN)
- set(GSSAPI_FLAVOR_HEIMDAL TRUE)
- endif()
- endif ()
- endif()
-endif (UNIX)
-
-find_path(GSSAPI_INCLUDE_DIR
- NAMES
- gssapi.h
- gssapi/gssapi.h
- PATHS
- ${GSSAPI_ROOT_DIR}/include
- ${_GSSAPI_INCLUDEDIR}
-)
-
-if (GSSAPI_FLAVOR_MIT)
- find_library(GSSAPI_LIBRARY
- NAMES
- gssapi_krb5
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(KRB5_LIBRARY
- NAMES
- krb5
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(K5CRYPTO_LIBRARY
- NAMES
- k5crypto
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(COM_ERR_LIBRARY
- NAMES
- com_err
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- if (GSSAPI_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${GSSAPI_LIBRARY}
- )
- endif (GSSAPI_LIBRARY)
-
- if (KRB5_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${KRB5_LIBRARY}
- )
- endif (KRB5_LIBRARY)
-
- if (K5CRYPTO_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${K5CRYPTO_LIBRARY}
- )
- endif (K5CRYPTO_LIBRARY)
-
- if (COM_ERR_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${COM_ERR_LIBRARY}
- )
- endif (COM_ERR_LIBRARY)
-endif (GSSAPI_FLAVOR_MIT)
-
-if (GSSAPI_FLAVOR_HEIMDAL)
- find_library(GSSAPI_LIBRARY
- NAMES
- gssapi
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(KRB5_LIBRARY
- NAMES
- krb5
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(HCRYPTO_LIBRARY
- NAMES
- hcrypto
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(COM_ERR_LIBRARY
- NAMES
- com_err
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(HEIMNTLM_LIBRARY
- NAMES
- heimntlm
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(HX509_LIBRARY
- NAMES
- hx509
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(ASN1_LIBRARY
- NAMES
- asn1
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(WIND_LIBRARY
- NAMES
- wind
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- find_library(ROKEN_LIBRARY
- NAMES
- roken
- PATHS
- ${GSSAPI_ROOT_DIR}/lib
- ${_GSSAPI_LIBDIR}
- )
-
- if (GSSAPI_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${GSSAPI_LIBRARY}
- )
- endif (GSSAPI_LIBRARY)
-
- if (KRB5_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${KRB5_LIBRARY}
- )
- endif (KRB5_LIBRARY)
-
- if (HCRYPTO_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${HCRYPTO_LIBRARY}
- )
- endif (HCRYPTO_LIBRARY)
-
- if (COM_ERR_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${COM_ERR_LIBRARY}
- )
- endif (COM_ERR_LIBRARY)
-
- if (HEIMNTLM_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${HEIMNTLM_LIBRARY}
- )
- endif (HEIMNTLM_LIBRARY)
-
- if (HX509_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${HX509_LIBRARY}
- )
- endif (HX509_LIBRARY)
-
- if (ASN1_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${ASN1_LIBRARY}
- )
- endif (ASN1_LIBRARY)
-
- if (WIND_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${WIND_LIBRARY}
- )
- endif (WIND_LIBRARY)
-
- if (ROKEN_LIBRARY)
- set(GSSAPI_LIBRARIES
- ${GSSAPI_LIBRARIES}
- ${WIND_LIBRARY}
- )
- endif (ROKEN_LIBRARY)
-endif (GSSAPI_FLAVOR_HEIMDAL)
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
-
-if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
- set(GSSAPI_FOUND TRUE)
-endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
-
-# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
-mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
+++ /dev/null
-# - Try to find http-parser
-#
-# Defines the following variables:
-#
-# HTTP_PARSER_FOUND - system has http-parser
-# HTTP_PARSER_INCLUDE_DIR - the http-parser include directory
-# HTTP_PARSER_LIBRARIES - Link these to use http-parser
-# HTTP_PARSER_VERSION_MAJOR - major version
-# HTTP_PARSER_VERSION_MINOR - minor version
-# HTTP_PARSER_VERSION_STRING - the version of http-parser found
-
-# Find the header and library
-FIND_PATH(HTTP_PARSER_INCLUDE_DIR NAMES http_parser.h)
-FIND_LIBRARY(HTTP_PARSER_LIBRARY NAMES http_parser libhttp_parser)
-
-# Found the header, read version
-if (HTTP_PARSER_INCLUDE_DIR AND EXISTS "${HTTP_PARSER_INCLUDE_DIR}/http_parser.h")
- FILE(READ "${HTTP_PARSER_INCLUDE_DIR}/http_parser.h" HTTP_PARSER_H)
- IF (HTTP_PARSER_H)
- STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MAJOR[\t ]+([0-9]+).*" "\\1" HTTP_PARSER_VERSION_MAJOR "${HTTP_PARSER_H}")
- STRING(REGEX REPLACE ".*#define[\t ]+HTTP_PARSER_VERSION_MINOR[\t ]+([0-9]+).*" "\\1" HTTP_PARSER_VERSION_MINOR "${HTTP_PARSER_H}")
- SET(HTTP_PARSER_VERSION_STRING "${HTTP_PARSER_VERSION_MAJOR}.${HTTP_PARSER_VERSION_MINOR}")
- ENDIF()
- UNSET(HTTP_PARSER_H)
-ENDIF()
-
-# Handle the QUIETLY and REQUIRED arguments and set HTTP_PARSER_FOUND
-# to TRUE if all listed variables are TRUE
-INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(HTTP_Parser REQUIRED_VARS HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY)
-
-# Hide advanced variables
-MARK_AS_ADVANCED(HTTP_PARSER_INCLUDE_DIR HTTP_PARSER_LIBRARY)
-
-# Set standard variables
-IF (HTTP_PARSER_FOUND)
- SET(HTTP_PARSER_LIBRARIES ${HTTP_PARSER_LIBRARY})
- set(HTTP_PARSER_INCLUDE_DIRS ${HTTP_PARSER_INCLUDE_DIR})
-ENDIF()
+++ /dev/null
-# - Try to find Iconv
-# Once done this will define
-#
-# ICONV_FOUND - system has Iconv
-# ICONV_INCLUDE_DIR - the Iconv include directory
-# ICONV_LIBRARIES - Link these to use Iconv
-#
-
-IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
- # Already in cache, be silent
- SET(ICONV_FIND_QUIETLY TRUE)
-ENDIF()
-
-FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
-CHECK_FUNCTION_EXISTS(iconv_open libc_has_iconv)
-FIND_LIBRARY(iconv_lib NAMES iconv libiconv libiconv-2 c)
-
-IF(ICONV_INCLUDE_DIR AND libc_has_iconv)
- SET(ICONV_FOUND TRUE)
- SET(ICONV_LIBRARIES "")
- IF(NOT ICONV_FIND_QUIETLY)
- MESSAGE(STATUS "Found Iconv: provided by libc")
- ENDIF(NOT ICONV_FIND_QUIETLY)
-ELSEIF(ICONV_INCLUDE_DIR AND iconv_lib)
- SET(ICONV_FOUND TRUE)
- # split iconv into -L and -l linker options, so we can
- # set them for pkg-config
- GET_FILENAME_COMPONENT(iconv_path ${iconv_lib} PATH)
- GET_FILENAME_COMPONENT(iconv_name ${iconv_lib} NAME_WE)
- STRING(REGEX REPLACE "^lib" "" iconv_name ${iconv_name})
- SET(ICONV_LIBRARIES "-L${iconv_path} -l${iconv_name}")
-
- IF(NOT ICONV_FIND_QUIETLY)
- MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
- ENDIF(NOT ICONV_FIND_QUIETLY)
-ELSE()
- IF(Iconv_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find Iconv")
- ENDIF(Iconv_FIND_REQUIRED)
-ENDIF()
-
-MARK_AS_ADVANCED(
- ICONV_INCLUDE_DIR
- ICONV_LIBRARIES
-)
+++ /dev/null
-INCLUDE(FindPkgConfig)
-
-# This function will find and set up a pkg-config based module.
-# If a pc-file was found, it will resolve library paths to
-# absolute paths. Furthermore, the function will automatically
-# fall back to use static libraries in case no dynamic libraries
-# were found.
-FUNCTION(FIND_PKGLIBRARIES prefix package)
- PKG_CHECK_MODULES(${prefix} ${package})
- IF(NOT ${prefix}_FOUND)
- RETURN()
- ENDIF()
-
- FOREACH(LIBRARY ${${prefix}_LIBRARIES})
- FIND_LIBRARY(${LIBRARY}_RESOLVED ${LIBRARY} PATHS ${${prefix}_LIBRARY_DIRS})
- IF(${${LIBRARY}_RESOLVED} STREQUAL "${LIBRARY}_RESOLVED-NOTFOUND")
- MESSAGE(FATAL_ERROR "could not resolve ${LIBRARY}")
- ENDIF()
- LIST(APPEND RESOLVED_LIBRARIES ${${LIBRARY}_RESOLVED})
- ENDFOREACH(LIBRARY)
-
- SET(${prefix}_FOUND 1 PARENT_SCOPE)
- SET(${prefix}_LIBRARIES ${RESOLVED_LIBRARIES} PARENT_SCOPE)
- SET(${prefix}_INCLUDE_DIRS ${${prefix}_INCLUDE_DIRS} PARENT_SCOPE)
- SET(${prefix}_LDFLAGS ${${prefix}_LDFLAGS} PARENT_SCOPE)
-
- MESSAGE(STATUS " Resolved libraries: ${RESOLVED_LIBRARIES}")
-ENDFUNCTION()
+++ /dev/null
-# Find Security.framework
-# This will define :
-#
-# SECURITY_FOUND
-# SECURITY_LIBRARIES
-# SECURITY_LDFLAGS
-# SECURITY_HAS_SSLCREATECONTEXT
-#
-
-FIND_PATH(SECURITY_INCLUDE_DIR NAMES Security/Security.h)
-FIND_LIBRARY(SECURITY_LIBRARIES NAMES Security)
-IF (SECURITY_INCLUDE_DIR AND SECURITY_LIBRARIES)
- IF (NOT Security_FIND_QUIETLY)
- MESSAGE("-- Found Security ${SECURITY_LIBRARIES}")
- ENDIF()
- SET(SECURITY_FOUND TRUE)
- SET(SECURITY_LDFLAGS "-framework Security")
- CHECK_LIBRARY_EXISTS("${SECURITY_LIBRARIES}" SSLCreateContext "Security/SecureTransport.h" SECURITY_HAS_SSLCREATECONTEXT)
-ENDIF ()
-
-IF (Security_FIND_REQUIRED AND NOT SECURITY_FOUND)
- MESSAGE(FATAL "-- Security not found")
-ENDIF()
-
-MARK_AS_ADVANCED(
- SECURITY_INCLUDE_DIR
- SECURITY_LIBRARIES
-)
+++ /dev/null
-CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtim "sys/types.h;sys/stat.h"
- HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C)
-CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtimespec "sys/types.h;sys/stat.h"
- HAVE_STRUCT_STAT_ST_MTIMESPEC LANGUAGE C)
-CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtime_nsec sys/stat.h
- HAVE_STRUCT_STAT_MTIME_NSEC LANGUAGE C)
-
-IF (HAVE_STRUCT_STAT_ST_MTIM)
- CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtim.tv_nsec sys/stat.h
- HAVE_STRUCT_STAT_NSEC LANGUAGE C)
-ELSEIF (HAVE_STRUCT_STAT_ST_MTIMESPEC)
- CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec sys/stat.h
- HAVE_STRUCT_STAT_NSEC LANGUAGE C)
-ELSE ()
- SET( HAVE_STRUCT_STAT_NSEC ON )
-ENDIF()
-
-IF (HAVE_STRUCT_STAT_NSEC OR WIN32)
- OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" ON )
-ENDIF()
+++ /dev/null
-# - Try to find mbedTLS
-# Once done this will define
-#
-# Read-Only variables
-# MBEDTLS_FOUND - system has mbedTLS
-# MBEDTLS_INCLUDE_DIR - the mbedTLS include directory
-# MBEDTLS_LIBRARY_DIR - the mbedTLS library directory
-# MBEDTLS_LIBRARIES - Link these to use mbedTLS
-# MBEDTLS_LIBRARY - path to mbedTLS library
-# MBEDX509_LIBRARY - path to mbedTLS X.509 library
-# MBEDCRYPTO_LIBRARY - path to mbedTLS Crypto library
-#
-# Hint
-# MBEDTLS_ROOT_DIR can be pointed to a local mbedTLS installation.
-
-SET(_MBEDTLS_ROOT_HINTS
- ${MBEDTLS_ROOT_DIR}
- ENV MBEDTLS_ROOT_DIR
-)
-
-SET(_MBEDTLS_ROOT_HINTS_AND_PATHS
- HINTS ${_MBEDTLS_ROOT_HINTS}
- PATHS ${_MBEDTLS_ROOT_PATHS}
-)
-
-FIND_PATH(MBEDTLS_INCLUDE_DIR
- NAMES mbedtls/version.h
- ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
- PATH_SUFFIXES include
-)
-
-IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES)
- # Already in cache, be silent
- SET(MBEDTLS_FIND_QUIETLY TRUE)
-ENDIF()
-
-FIND_LIBRARY(MBEDTLS_LIBRARY
- NAMES mbedtls libmbedtls
- ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
- PATH_SUFFIXES library
-)
-FIND_LIBRARY(MBEDX509_LIBRARY
- NAMES mbedx509 libmbedx509
- ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
- PATH_SUFFIXES library
-)
-FIND_LIBRARY(MBEDCRYPTO_LIBRARY
- NAMES mbedcrypto libmbedcrypto
- ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
- PATH_SUFFIXES library
-)
-
-IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY)
- SET(MBEDTLS_FOUND TRUE)
-ENDIF()
-
-IF(MBEDTLS_FOUND)
- # split mbedTLS into -L and -l linker options, so we can set them for pkg-config
- GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_DIR ${MBEDTLS_LIBRARY} PATH)
- GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY} NAME_WE)
- GET_FILENAME_COMPONENT(MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY} NAME_WE)
- GET_FILENAME_COMPONENT(MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY} NAME_WE)
- STRING(REGEX REPLACE "^lib" "" MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY_FILE})
- STRING(REGEX REPLACE "^lib" "" MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY_FILE})
- STRING(REGEX REPLACE "^lib" "" MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY_FILE})
- SET(MBEDTLS_LIBRARIES "-L${MBEDTLS_LIBRARY_DIR} -l${MBEDTLS_LIBRARY_FILE} -l${MBEDX509_LIBRARY_FILE} -l${MBEDCRYPTO_LIBRARY_FILE}")
-
- IF(NOT MBEDTLS_FIND_QUIETLY)
- MESSAGE(STATUS "Found mbedTLS:")
- FILE(READ ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h MBEDTLSCONTENT)
- STRING(REGEX MATCH "MBEDTLS_VERSION_STRING +\"[0-9|.]+\"" MBEDTLSMATCH ${MBEDTLSCONTENT})
- IF (MBEDTLSMATCH)
- STRING(REGEX REPLACE "MBEDTLS_VERSION_STRING +\"([0-9|.]+)\"" "\\1" MBEDTLS_VERSION ${MBEDTLSMATCH})
- MESSAGE(STATUS " version ${MBEDTLS_VERSION}")
- ENDIF(MBEDTLSMATCH)
- MESSAGE(STATUS " TLS: ${MBEDTLS_LIBRARY}")
- MESSAGE(STATUS " X509: ${MBEDX509_LIBRARY}")
- MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
- ENDIF(NOT MBEDTLS_FIND_QUIETLY)
-ELSE(MBEDTLS_FOUND)
- IF(MBEDTLS_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find mbedTLS")
- ENDIF(MBEDTLS_FIND_REQUIRED)
-ENDIF(MBEDTLS_FOUND)
-
-MARK_AS_ADVANCED(
- MBEDTLS_INCLUDE_DIR
- MBEDTLS_LIBRARY_DIR
- MBEDTLS_LIBRARIES
- MBEDTLS_LIBRARY
- MBEDX509_LIBRARY
- MBEDCRYPTO_LIBRARY
-)
+++ /dev/null
-# This function splits the sources files up into their appropriate
-# subdirectories. This is especially useful for IDEs like Xcode and
-# Visual Studio, so that you can navigate into the libgit2_clar project,
-# and see the folders within the tests folder (instead of just seeing all
-# source and tests in a single folder.)
-FUNCTION(IDE_SPLIT_SOURCES target)
- IF(MSVC_IDE OR CMAKE_GENERATOR STREQUAL Xcode)
- GET_TARGET_PROPERTY(sources ${target} SOURCES)
- FOREACH(source ${sources})
- IF(source MATCHES ".*/")
- STRING(REPLACE ${libgit2_SOURCE_DIR}/ "" rel ${source})
- IF(rel)
- STRING(REGEX REPLACE "/([^/]*)$" "" rel ${rel})
- IF(rel)
- STRING(REPLACE "/" "\\\\" rel ${rel})
- SOURCE_GROUP(${rel} FILES ${source})
- ENDIF()
- ENDIF()
- ENDIF()
- ENDFOREACH()
- ENDIF()
-ENDFUNCTION()
--- /dev/null
+# pkg-config file generation
+#
+
+function(pkg_build_config)
+ set(options)
+ set(oneValueArgs NAME DESCRIPTION VERSION FILENAME LIBS_SELF)
+ set(multiValueArgs LIBS PRIVATE_LIBS REQUIRES CFLAGS)
+
+ cmake_parse_arguments(PKGCONFIG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if (NOT DEFINED PKGCONFIG_FILENAME AND DEFINED PKGCONFIG_NAME)
+ set(PKGCONFIG_FILENAME ${PKGCONFIG_NAME})
+ endif()
+ if (NOT DEFINED PKGCONFIG_FILENAME)
+ message(FATAL_ERROR "Missing FILENAME argument")
+ endif()
+ set(PKGCONFIG_FILE "${PROJECT_BINARY_DIR}/${PKGCONFIG_FILENAME}.pc")
+
+ if (NOT DEFINED PKGCONFIG_DESCRIPTION)
+ message(FATAL_ERROR "Missing DESCRIPTION argument")
+ endif()
+
+ if (NOT DEFINED PKGCONFIG_VERSION)
+ message(FATAL_ERROR "Missing VERSION argument")
+ endif()
+
+ # Write .pc "header"
+ file(WRITE "${PKGCONFIG_FILE}"
+ "prefix=\"${CMAKE_INSTALL_PREFIX}\"\n"
+ "libdir=\"${CMAKE_INSTALL_FULL_LIBDIR}\"\n"
+ "includedir=\"${CMAKE_INSTALL_FULL_INCLUDEDIR}\"\n"
+ "\n"
+ "Name: ${PKGCONFIG_NAME}\n"
+ "Description: ${PKGCONFIG_DESCRIPTION}\n"
+ "Version: ${PKGCONFIG_VERSION}\n"
+ )
+
+ # Prepare Libs
+ if(NOT DEFINED PKGCONFIG_LIBS_SELF)
+ set(PKGCONFIG_LIBS_SELF "${PKGCONFIG_FILE}")
+ endif()
+
+ if(NOT DEFINED PKGCONFIG_LIBS)
+ set(PKGCONFIG_LIBS "-l${PKGCONFIG_LIBS_SELF}")
+ else()
+ list(INSERT PKGCONFIG_LIBS 0 "-l${PKGCONFIG_LIBS_SELF}")
+ endif()
+
+ list(REMOVE_DUPLICATES PKGCONFIG_LIBS)
+ string(REPLACE ";" " " PKGCONFIG_LIBS "${PKGCONFIG_LIBS}")
+ file(APPEND "${PKGCONFIG_FILE}" "Libs: -L\${libdir} ${PKGCONFIG_LIBS}\n")
+
+ # Prepare Libs.private
+ if(DEFINED PKGCONFIG_PRIVATE_LIBS)
+ list(REMOVE_DUPLICATES PKGCONFIG_PRIVATE_LIBS)
+ string(REPLACE ";" " " PKGCONFIG_PRIVATE_LIBS "${PKGCONFIG_PRIVATE_LIBS}")
+ file(APPEND "${PKGCONFIG_FILE}" "Libs.private: ${PKGCONFIG_PRIVATE_LIBS}\n")
+ endif()
+
+ # Prepare Requires.private
+ if(DEFINED PKGCONFIG_REQUIRES)
+ list(REMOVE_DUPLICATES PKGCONFIG_REQUIRES)
+ string(REPLACE ";" " " PKGCONFIG_REQUIRES "${PKGCONFIG_REQUIRES}")
+ file(APPEND "${PKGCONFIG_FILE}" "Requires.private: ${PKGCONFIG_REQUIRES}\n")
+ endif()
+
+ # Prepare Cflags
+ if(DEFINED PKGCONFIG_CFLAGS)
+ string(REPLACE ";" " " PKGCONFIG_CFLAGS "${PKGCONFIG_CFLAGS}")
+ else()
+ set(PKGCONFIG_CFLAGS "")
+ endif()
+ file(APPEND "${PKGCONFIG_FILE}" "Cflags: -I\${includedir} ${PKGCONFIG_CFLAGS}\n")
+
+ # Install .pc file
+ install(FILES "${PKGCONFIG_FILE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endfunction()
--- /dev/null
+FUNCTION(SanitizeBool VAR)
+ STRING(TOLOWER "${${VAR}}" VALUE)
+ IF(VALUE STREQUAL "on")
+ SET(${VAR} "ON" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "yes")
+ SET(${VAR} "ON" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "true")
+ SET(${VAR} "ON" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "1")
+ SET(${VAR} "ON" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "off")
+ SET(${VAR} "OFF" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "no")
+ SET(${VAR} "OFF" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "false")
+ SET(${VAR} "OFF" PARENT_SCOPE)
+ ELSEIF(VALUE STREQUAL "0")
+ SET(${VAR} "OFF" PARENT_SCOPE)
+ ENDIF()
+ENDFUNCTION()
--- /dev/null
+INCLUDE(SanitizeBool)
+
+# We try to find any packages our backends might use
+FIND_PACKAGE(GSSAPI)
+IF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ INCLUDE(FindGSSFramework)
+ENDIF()
+
+IF(USE_GSSAPI)
+ # Auto-select GSS backend
+ SanitizeBool(USE_GSSAPI)
+ IF (USE_GSSAPI STREQUAL ON)
+ IF (GSSFRAMEWORK_FOUND)
+ SET(USE_GSSAPI "GSS.framework")
+ ELSEIF(GSSAPI_FOUND)
+ SET(USE_GSSAPI "gssapi")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Unable to autodetect a usable GSS backend."
+ "Please pass the backend name explicitly (-DUSE_GSS=backend)")
+ ENDIF()
+ ENDIF()
+
+ # Check that we can find what's required for the selected backend
+ IF (USE_GSSAPI STREQUAL "GSS.framework")
+ IF (NOT GSSFRAMEWORK_FOUND)
+ MESSAGE(FATAL_ERROR "Asked for GSS.framework backend, but it wasn't found")
+ ENDIF()
+
+ LIST(APPEND LIBGIT2_LIBS ${GSSFRAMEWORK_LIBRARIES})
+
+ SET(GIT_GSSFRAMEWORK 1)
+ ADD_FEATURE_INFO(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${USE_GSSAPI})")
+ ELSEIF (USE_GSSAPI STREQUAL "gssapi")
+ IF (NOT GSSAPI_FOUND)
+ MESSAGE(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found")
+ ENDIF()
+
+ LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES})
+
+ SET(GIT_GSSAPI 1)
+ ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${USE_GSSAPI})")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Asked for backend ${USE_GSSAPI} but it wasn't found")
+ ENDIF()
+ELSE()
+ SET(GIT_GSSAPI 0)
+ ADD_FEATURE_INFO(SPNEGO NO "SPNEGO authentication support")
+ENDIF()
--- /dev/null
+INCLUDE(SanitizeBool)
+
+# We try to find any packages our backends might use
+FIND_PACKAGE(OpenSSL)
+FIND_PACKAGE(mbedTLS)
+IF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
+ FIND_PACKAGE(Security)
+ FIND_PACKAGE(CoreFoundation)
+ENDIF()
+
+IF(USE_HTTPS)
+ # Auto-select TLS backend
+ SanitizeBool(USE_HTTPS)
+ IF (USE_HTTPS STREQUAL ON)
+ IF (SECURITY_FOUND)
+ IF (SECURITY_HAS_SSLCREATECONTEXT)
+ SET(USE_HTTPS "SecureTransport")
+ ELSE()
+ MESSAGE(STATUS "Security framework is too old, falling back to OpenSSL")
+ SET(USE_HTTPS "OpenSSL")
+ ENDIF()
+ ELSEIF (WINHTTP)
+ SET(USE_HTTPS "WinHTTP")
+ ELSEIF(OPENSSL_FOUND)
+ SET(USE_HTTPS "OpenSSL")
+ ELSEIF(MBEDTLS_FOUND)
+ SET(USE_HTTPS "mbedTLS")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Unable to autodetect a usable HTTPS backend."
+ "Please pass the backend name explicitly (-DUSE_HTTPS=backend)")
+ ENDIF()
+ ENDIF()
+
+ # Check that we can find what's required for the selected backend
+ IF (USE_HTTPS STREQUAL "SecureTransport")
+ IF (NOT COREFOUNDATION_FOUND)
+ MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, CoreFoundation.framework not found")
+ ENDIF()
+ IF (NOT SECURITY_FOUND)
+ MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, Security.framework not found")
+ ENDIF()
+ IF (NOT SECURITY_HAS_SSLCREATECONTEXT)
+ MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, SSLCreateContext not supported")
+ ENDIF()
+
+ SET(GIT_SECURE_TRANSPORT 1)
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR})
+ LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS})
+ LIST(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS})
+ ELSEIF (USE_HTTPS STREQUAL "OpenSSL")
+ IF (NOT OPENSSL_FOUND)
+ MESSAGE(FATAL_ERROR "Asked for OpenSSL TLS backend, but it wasn't found")
+ ENDIF()
+
+ SET(GIT_OPENSSL 1)
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR})
+ LIST(APPEND LIBGIT2_LIBS ${OPENSSL_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS})
+ LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
+ ELSEIF(USE_HTTPS STREQUAL "mbedTLS")
+ IF (NOT MBEDTLS_FOUND)
+ MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found")
+ ENDIF()
+
+ IF(NOT CERT_LOCATION)
+ MESSAGE(STATUS "Auto-detecting default certificates location")
+ IF(CMAKE_SYSTEM_NAME MATCHES Darwin)
+ # Check for an Homebrew installation
+ SET(OPENSSL_CMD "/usr/local/opt/openssl/bin/openssl")
+ ELSE()
+ SET(OPENSSL_CMD "openssl")
+ ENDIF()
+ EXECUTE_PROCESS(COMMAND ${OPENSSL_CMD} version -d OUTPUT_VARIABLE OPENSSL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
+ IF(OPENSSL_DIR)
+ STRING(REGEX REPLACE "^OPENSSLDIR: \"(.*)\"$" "\\1/" OPENSSL_DIR ${OPENSSL_DIR})
+
+ SET(OPENSSL_CA_LOCATIONS
+ "ca-bundle.pem" # OpenSUSE Leap 42.1
+ "cert.pem" # Ubuntu 14.04, FreeBSD
+ "certs/ca-certificates.crt" # Ubuntu 16.04
+ "certs/ca.pem" # Debian 7
+ )
+ FOREACH(SUFFIX IN LISTS OPENSSL_CA_LOCATIONS)
+ SET(LOC "${OPENSSL_DIR}${SUFFIX}")
+ IF(NOT CERT_LOCATION AND EXISTS "${OPENSSL_DIR}${SUFFIX}")
+ SET(CERT_LOCATION ${LOC})
+ ENDIF()
+ ENDFOREACH()
+ ELSE()
+ MESSAGE(FATAL_ERROR "Unable to find OpenSSL executable. Please provide default certificate location via CERT_LOCATION")
+ ENDIF()
+ ENDIF()
+
+ IF(CERT_LOCATION)
+ IF(NOT EXISTS ${CERT_LOCATION})
+ MESSAGE(FATAL_ERROR "Cannot use CERT_LOCATION=${CERT_LOCATION} as it doesn't exist")
+ ENDIF()
+ ADD_FEATURE_INFO(CERT_LOCATION ON "using certificates from ${CERT_LOCATION}")
+ ADD_DEFINITIONS(-DGIT_DEFAULT_CERT_LOCATION="${CERT_LOCATION}")
+ ENDIF()
+
+ SET(GIT_MBEDTLS 1)
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR})
+ LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
+ # mbedTLS has no pkgconfig file, hence we can't require it
+ # https://github.com/ARMmbed/mbedtls/issues/228
+ # For now, pass its link flags as our own
+ LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
+ ELSEIF (USE_HTTPS STREQUAL "WinHTTP")
+ # WinHTTP setup was handled in the WinHTTP-specific block above
+ ELSE()
+ MESSAGE(FATAL_ERROR "Asked for backend ${USE_HTTPS} but it wasn't found")
+ ENDIF()
+
+ SET(GIT_HTTPS 1)
+ ADD_FEATURE_INFO(HTTPS GIT_HTTPS "using ${USE_HTTPS}")
+ELSE()
+ SET(GIT_HTTPS 0)
+ ADD_FEATURE_INFO(HTTPS NO "")
+ENDIF()
--- /dev/null
+# Select a hash backend
+
+INCLUDE(SanitizeBool)
+
+# USE_SHA1=CollisionDetection(ON)/HTTPS/Generic/OFF
+
+SanitizeBool(USE_SHA1)
+IF(USE_SHA1 STREQUAL ON)
+ SET(USE_SHA1 "CollisionDetection")
+ELSEIF(USE_SHA1 STREQUAL "HTTPS")
+ IF(USE_HTTPS STREQUAL "SecureTransport")
+ SET(USE_SHA1 "CommonCrypto")
+ ELSEIF(USE_HTTPS STREQUAL "WinHTTP")
+ SET(USE_SHA1 "Win32")
+ ELSEIF(USE_HTTPS)
+ SET(USE_SHA1 ${USE_HTTPS})
+ ELSE()
+ SET(USE_SHA1 "CollisionDetection")
+ ENDIF()
+ENDIF()
+
+IF(USE_SHA1 STREQUAL "CollisionDetection")
+ SET(GIT_SHA1_COLLISIONDETECT 1)
+ ADD_DEFINITIONS(-DSHA1DC_NO_STANDARD_INCLUDES=1)
+ ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_SHA1_C=\"common.h\")
+ ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"common.h\")
+ FILE(GLOB SRC_SHA1 hash/sha1/collisiondetect.* hash/sha1/sha1dc/*)
+ELSEIF(USE_SHA1 STREQUAL "OpenSSL")
+ # OPENSSL_FOUND should already be set, we're checking USE_HTTPS
+
+ SET(GIT_SHA1_OPENSSL 1)
+ IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ LIST(APPEND LIBGIT2_PC_LIBS "-lssl")
+ ELSE()
+ LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
+ ENDIF()
+ FILE(GLOB SRC_SHA1 hash/sha1/openssl.*)
+ELSEIF(USE_SHA1 STREQUAL "CommonCrypto")
+ SET(GIT_SHA1_COMMON_CRYPTO 1)
+ FILE(GLOB SRC_SHA1 hash/sha1/common_crypto.*)
+ELSEIF(USE_SHA1 STREQUAL "mbedTLS")
+ SET(GIT_SHA1_MBEDTLS 1)
+ FILE(GLOB SRC_SHA1 hash/sha1/mbedtls.*)
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR})
+ LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
+ # mbedTLS has no pkgconfig file, hence we can't require it
+ # https://github.com/ARMmbed/mbedtls/issues/228
+ # For now, pass its link flags as our own
+ LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
+ELSEIF(USE_SHA1 STREQUAL "Win32")
+ SET(GIT_SHA1_WIN32 1)
+ FILE(GLOB SRC_SHA1 hash/sha1/win32.*)
+ELSEIF(USE_SHA1 STREQUAL "Generic")
+ FILE(GLOB SRC_SHA1 hash/sha1/generic.*)
+ELSE()
+ MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}")
+ENDIF()
+
+list(SORT SRC_SHA1)
+
+ADD_FEATURE_INFO(SHA ON "using ${USE_SHA1}")
-v0.28.4
---------
+v1.1
+----
-This is a security release fixing the following issues:
+This is release v1.1, "Fernweh".
+
+### Changes or improvements
+
+* Our bundled PCRE dependency has been updated to 8.44.
+
+* The `refs/remotes/origin/HEAD` file will be created at clone time to
+ point to the origin's default branch.
+
+* libgit2 now uses the `__atomic_` intrinsics instead of `__sync_`
+ intrinsics on supported gcc and clang versions.
+
+* The `init.defaultBranch` setting is now respected and `master` is
+ no longer the hardcoded as the default branch name.
+
+* Patch files that do not contain an `index` line can now be parsed.
+
+* Configuration files with multi-line values can now contain quotes
+ split across multiple lines.
+
+* Windows clients now attempt to use TLS1.3 when available.
+
+* Servers that request an upgrade to a newer HTTP version are
+ silently ignored instead of erroneously failing.
+
+* Users can pass `NULL` to the options argument to
+ `git_describe_commit`.
+
+* Clones and fetches of very large packfiles now succeeds on 32-bit
+ platforms.
+
+* Custom reference database backends can now handle the repository's
+ `HEAD` correctly.
+
+* Repositories with a large number of packfiles no longer exhaust the
+ number of file descriptors.
+
+* The test framework now supports TAP output when the `-t` flag is
+ specified.
+
+* The test framework can now specify an exact match to a test
+ function using a trailing `$`.
+
+* All checkout types support `GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH`.
+
+* `git_blame` now can ignore whitespace changes using the option
+ `GIT_BLAME_IGNORE_WHITESPACE`.
+
+* Several new examples have been created, including an examples for
+ commit, add and push.
+
+* Mode changes during rename are now supported in patch application.
+
+* `git_checkout_head` now correctly removes untracked files in a
+ subdirectory when the `FORCE | REMOVE_UNTRACKED` options are specified.
+
+v1.0.1
+------
+
+This is a bugfix release with the following changes:
+
+- Calculating information about renamed files during merges is more
+ efficient because dissimilarity about files is now being cached and
+ no longer needs to be recomputed.
+
+- The `git_worktree_prune_init_options` has been correctly restored for
+ backward compatibility. In v1.0 it was incorrectly deprecated with a
+ typo.
+
+- The optional ntlmclient dependency now supports NetBSD.
+
+- A bug where attempting to stash on a bare repository may have failed
+ has been fixed.
+
+- Configuration files that are unreadable due to permissions are now
+ silently ignored, and treated as if they do not exist. This matches
+ git's behavior; previously this case would have been an error.
+
+- v4 index files are now correctly written; previously we would read
+ them correctly but would not write the prefix-compression accurately,
+ causing corruption.
+
+- A bug where the smart HTTP transport could not read large data packets
+ has been fixed. Previously, fetching from servers like Gerrit, that
+ sent large data packets, would error.
+
+v1.0
+----
+
+This is release v1.0 "Luftschloss", which is the first stabe release of
+libgit2. The API will stay compatible across all releases of the same major
+version. This release includes bugfixes only and supersedes v0.99, which will
+stop being maintained. Both v0.27 and v0.28 stay supported in accordance with
+our release policy.
+
+### Changes or improvements
+
+- CMake was converted to make use of the GNUInstallDirs module for both our
+ pkgconfig and install targets in favor of our custom build options
+ `BIN_INSTALL_DIR`, `LIB_INSTALL_DIR` and `INCLUDE_INSTALL_DIR`. Instead, you
+ can now use CMakes standard variables `CMAKE_INSTALL_BINDIR`,
+ `CMAKE_INSTALL_LIBDIR` and `CMAKE_INSTALL_INCLUDEDIR`.
+
+- Some CMake build options accepted either a specific value or a boolean value
+ to disable the option altogether or use automatic detection. We only accepted
+ "ON" or "OFF", but none of the other values CMake recognizes as boolean. This
+ was aligned with CMake's understanding of booleans.
+
+- The installed pkgconfig file contained incorrect values for both `libdir` and
+ `includedir` variables.
+
+- If using pcre2 for regular expressions, then we incorrectly added "pcre2"
+ instead of "pcre2-8" to our pkgconfig dependencies, which was corrected.
+
+- Fixed building the bundled ntlmclient dependency on FreeBSD, OpenBSD and
+ SunOS.
+
+- When writing symlinks on Windows, we incorrectly handled relative symlink
+ targets, which was corrected.
+
+- When using the HTTP protocol via macOS' SecureTransport implementation, reads
+ could stall at the end of the session and only continue after a timeout of 60
+ seconds was reached.
+
+- The filesystem-based reference callback didn't corectly initialize the backend
+ version.
+
+- A segmentation fault was fixed when calling `git_blame_buffer()` for files
+ that were modified and added to the index.
+
+- A backwards-incompatible change was introduced when we moved some structures
+ from "git2/credentials.h" into "git2/sys/credentials.h". This was fixed in the
+ case where you do not use hard deprecation.
+
+- Improved error handling in various places.
+
+
+v0.99
+-----
+
+This is v0.99 "Torschlusspanik". This will be the last minor release
+before libgit2 v1.0. We expect to only respond to bugs in this release,
+to stabilize it for next major release.
+
+It contains significant refactorings, but is expected to be API-compatible
+with v0.28.0.
+
+### Changes or improvements
+
+* When fetching from an anonymous remote using a URL with authentication
+ information provided in the URL (eg `https://foo:bar@example.com/repo`),
+ we would erroneously include the literal URL in the FETCH_HEAD file.
+ We now remove that to match git's behavior.
+
+* Some credential structures, enums and values have been renamed:
+ `git_cred` is now `git_credential`. `git_credtype_t` is now
+ `git_credential_t`. Functions and types beginning with
+ `git_cred_` now begin with `git_credential`, and constants beginning
+ with `GIT_CREDTYPE` now begin with `GIT_CREDENTIAL`. The former names
+ are deprecated.
+
+* Several function signatures have been changed to return an `int` to
+ indicate error conditions. We encourage you to check them for errors
+ in the standard way.
+
+ * `git_attr_cache_flush`
+ * `git_error_set_str`
+ * `git_index_name_clear`
+ * `git_index_reuc_clear`
+ * `git_libgit2_version`
+ * `git_mempack_reset`
+ * `git_oid_cpy`
+ * `git_oid_fmt`
+ * `git_oid_fromraw`
+ * `git_oid_nfmt`
+ * `git_oid_pathfmt`
+ * `git_remote_stop`
+ * `git_remote_disconnect`
+ * `git_repository__cleanup`
+ * `git_repository_set_config`
+ * `git_repository_set_index`
+ * `git_repository_set_odb`
+ * `git_repository_set_refdb`
+ * `git_revwalk_reset`
+ * `git_revwalk_simplify_first_parent`
+ * `git_revwalk_sorting`
+ * `git_treebuilder_clear`
+ * `git_treebuilder_filter`
+
+* The NTLM and Negotiate authentication mechanisms are now supported when
+ talking to git implementations hosted on Apache or nginx servers.
+
+* The `HEAD` symbolic reference can no longer be deleted.
+
+* `git_merge_driver_source_repo` no longer returns a `const git_repository *`,
+ it now returns a non-`const` `git_repository *`.
+
+* Relative symbolic links are now supported on Windows when `core.symlinks`
+ is enabled.
+
+* Servers that provide query parameters with a redirect are now supported.
+
+* `git_submodule_sync` will now resolve relative URLs.
+
+* When creating git endpoint URLs, double-slashes are no longer used when
+ the given git URL has a trailing slash.
+
+* On Windows, a `DllMain` function is no longer included and thread-local
+ storage has moved to fiber-local storage in order to prevent race
+ conditions during shutdown.
+
+* The tracing mechanism (`GIT_TRACE`) is now enabled by default and does
+ not need to be explicitly enabled in CMake.
+
+* The size of Git objects is now represented by `git_object_size_t`
+ instead of `off_t`.
+
+* Binary patches without data can now be parsed.
+
+* A configuration snapshot can now be created from another configuration
+ snapshot, not just a "true" configuration object.
+
+* The `git_commit_with_signature` API will now ensure that referenced
+ objects exist in the object database.
+
+* Stash messages containing newlines will now be replaced with spaces;
+ they will no longer be (erroneously) written to the repository.
+
+* `git_commit_create_with_signature` now verifies the commit information
+ to ensure that it points to a valid tree and valid parents.
+
+* `git_apply` has an option `GIT_APPLY_CHECK` that will only do a dry-run.
+ The index and working directory will remain unmodified, and application
+ will report if it would have worked.
+
+* Patches produced by Mercurial (those that lack some git extended headers)
+ can now be parsed and applied.
+
+* Reference locks are obeyed correctly on POSIX platforms, instead of
+ being removed.
+
+* Patches with empty new files can now be read and applied.
+
+* `git_apply_to_tree` can now correctly apply patches that add new files.
+
+* The program data configuration on Windows (`C:\ProgramData\Git\config`)
+ must be owned by an administrator, a system account or the current user
+ to be read.
+
+* `git_blob_filtered_content` is now deprecated in favor of `git_blob_filter`.
+
+* Configuration files can now be included conditionally using the
+ `onbranch` conditional.
+
+* Checkout can now properly create and remove symbolic links to directories
+ on Windows.
+
+* Stash no longer recomputes trees when committing a worktree, for
+ improved performance.
+
+* Repository templates can now include a `HEAD` file to default the
+ initial default branch.
+
+* Some configuration structures, enums and values have been renamed:
+ `git_cvar_map` is now `git_configmap`, `git_cvar_t` is now
+ `git_configmap_t`, `GIT_CVAR_FALSE` is now `GIT_CONFIGMAP_FALSE`,
+ `GIT_CVAR_TRUE` is now `GIT_CONFIGMAP_TRUE`, `GIT_CVAR_INT32` is now
+ `GIT_CONFIGMAP_INT32`, and `GIT_CVAR_STRING` is now `GIT_CONFIGMAP_STRING`.
+ The former names are deprecated.
+
+* Repositories can now be created at the root of a Windows drive.
+
+* Configuration lookups are now more efficiently cached.
+
+* `git_commit_create_with_signature` now supports a `NULL` signature,
+ which will create a commit without adding a signature.
+
+* When a repository lacks an `info` "common directory", we will no
+ longer erroneously return `GIT_ENOTFOUND` for all attribute lookups.
+
+* Several attribute macros have been renamed: `GIT_ATTR_TRUE` is now
+ `GIT_ATTR_IS_TRUE`, `GIT_ATTR_FALSE` is now `GIT_ATTR_IS_FALSE`,
+ `GIT_ATTR_UNSPECIFIED` is now `GIT_ATTR_IS_UNSPECIFIED`. The
+ attribute enum `git_attr_t` is now `git_attr_value_t` and its
+ values have been renamed: `GIT_ATTR_UNSPECIFIED_T` is now
+ `GIT_ATTR_VALUE_UNSPECIFIED`, `GIT_ATTR_TRUE_T` is now
+ `GIT_ATTR_VALUE_TRUE`, `GIT_ATTR_FALSE_T` is now `GIT_ATTR_VALUE_FALSE`,
+ and `GIT_ATTR_VALUE_T` is now `GIT_ATTR_VALUE_STRING`. The
+ former names are deprecated.
+
+* `git_object__size` is now `git_object_size`. The former name is
+ deprecated.
+
+* `git_tag_create_frombuffer` is now `git_tag_create_from_buffer`. The
+ former name is deprecated.
+
+* Several blob creation functions have been renamed:
+ `git_blob_create_frombuffer` is now named `git_blob_create_from_buffer`,
+ `git_blob_create_fromdisk` is now named `git_blob_create_from_disk`,
+ `git_blob_create_fromworkdir` is now named `git_blob_create_from_workdir`,
+ `git_blob_create_fromstream` is now named `git_blob_create_from_stream`,
+ and `git_blob_create_fromstream_commit` is now named
+ `git_blob_create_from_stream_commit`. The former names are deprecated.
+
+* The function `git_oid_iszero` is now named `git_oid_is_zero`. The
+ former name is deprecated.
+
+* Pattern matching is now done using `wildmatch` instead of `fnmatch`
+ for compatibility with git.
+
+* The option initialization functions suffixed by `init_options` are now
+ suffixed with `options_init`. (For example, `git_checkout_init_options`
+ is now `git_checkout_options_init`.) The former names are deprecated.
+
+* NTLM2 authentication is now supported on non-Windows platforms.
+
+* The `git_cred_sign_callback` callback is now named `git_cred_sign_cb`.
+ The `git_cred_ssh_interactive_callback` callback is now named
+ `git_cred_ssh_interactive_cb`.
+
+* Ignore files now:
+
+ * honor escaped trailing whitespace.
+ * do not incorrectly negate sibling paths of a negated pattern.
+ * honor rules that stop ignoring files after a wildcard
+
+* Attribute files now:
+
+ * honor leading and trailing whitespace.
+ * treat paths beginning with `\` as absolute only on Windows.
+ * properly handle escaped characters.
+ * stop reading macros defined in subdirectories
+
+* The C locale is now correctly used when parsing regular expressions.
+
+* The system PCRE2 or PCRE regular expression libraries are now used
+ when `regcomp_l` is not available on the system. If none of these
+ are available on the system, an included version of PCRE is used.
+
+* Wildcards in reference specifications are now supported beyond simply
+ a bare wildcard (`*`) for compatibility with git.
+
+* When `git_ignore_path_is_ignored` is provided a path with a trailing
+ slash (eg, `dir/`), it will now treat it as a directory for the
+ purposes of ignore matching.
+
+* Patches that add or remove a file with a space in the path can now
+ be correctly parsed.
+
+* The `git_remote_completion_type` type is now `git_remote_completion_t`.
+ The former name is deprecated.
+
+* The `git_odb_backend_malloc` is now `git_odb_backend_data_alloc`. The
+ former name is deprecated.
+
+* The `git_transfer_progress_cb` callback is now `git_indexer_progress_cb`
+ and the `git_transfer_progress` structure is now `git_indexer_progress`.
+ The former names are deprecated.
+
+* The example projects are now contained in a single `lg2` executable
+ for ease of use.
+
+* libgit2 now correctly handles more URLs, such as
+ `http://example.com:/repo.git` (colon but no port),
+ `http://example.com` (no path),
+ and `http://example.com:8080/` (path is /, nonstandard port).
+
+* A carefully constructed commit object with a very large number
+ of parents may lead to potential out-of-bounds writes or
+ potential denial of service.
+
+* The ProgramData configuration file is always read for compatibility
+ with Git for Windows and Portable Git installations. The ProgramData
+ location is not necessarily writable only by administrators, so we
+ now ensure that the configuration file is owned by the administrator
+ or the current user.
+
+### API additions
+
+* The SSH host key now supports SHA-256 when `GIT_CERT_SSH_SHA256` is set.
+
+* The diff format option `GIT_DIFF_FORMAT_PATCH_ID` can now be used to
+ emit an output like `git patch-id`.
+
+* The `git_apply_options_init` function will initialize a
+ `git_apply_options` structure.
+
+* The remote callbacks structure adds a `git_url_resolve_cb` callback
+ that is invoked when connecting to a server, so that applications
+ may edit or replace the URL before connection.
+
+* The information about the original `HEAD` in a rebase operation is
+ available with `git_rebase_orig_head_name`. Its ID is available with
+ `git_rebase_orig_head_id`. The `onto` reference name is available with
+ `git_rebase_onto_name` and its ID is available with `git_rebase_onto_id`.
+
+* ODB backends can now free backend data when an error occurs during its
+ backend data creation using `git_odb_backend_data_free`.
+
+* Options may be specified to `git_repository_foreach_head` to control
+ its behavior: `GIT_REPOSITORY_FOREACH_HEAD_SKIP_REPO` will not skip
+ the main repository's HEAD reference, while
+ `GIT_REPOSITORY_FOREACH_HEAD_SKIP_WORKTREES` will now skip the
+ worktree HEAD references.
+
+* The `GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS` option can be specified to
+ `git_libgit2_opts()` to avoid looking for `.keep` files that correspond
+ to packfiles. This setting can improve performance when packfiles are
+ stored on high-latency filesystems like network filesystems.
+
+* Blobs can now be filtered with `git_blob_filter`, which allows for
+ options to be set with `git_blob_filter_options`, including
+ `GIT_FILTER_NO_SYSTEM_ATTRIBUTES` to disable filtering with system-level
+ attributes in `/etc/gitattributes` and `GIT_ATTR_CHECK_INCLUDE_HEAD` to
+ enable filtering with `.gitattributes` files in the HEAD revision.
+
+### API removals
+
+* The unused `git_headlist_cb` function declaration was removed.
+
+* The unused `git_time_monotonic` API is removed.
+
+* The erroneously exported `inttypes.h` header was removed.
+
+# Security Fixes
- CVE-2019-1348: the fast-import stream command "feature
export-marks=path" allows writing to arbitrary file paths. As
recursive submodule clones manually are encouraged to review
their implementation for this vulnerability.
-v0.28.3
--------
-
-This is a security release fixing the following issues:
-
-* A carefully constructed commit object with a very large number
- of parents may lead to potential out-of-bounds writes or
- potential denial of service.
-
-* The ProgramData configuration file is always read for compatibility
- with Git for Windows and Portable Git installations. The ProgramData
- location is not necessarily writable only by administrators, so we
- now ensure that the configuration file is owned by the administrator
- or the current user.
-
-v0.28.2
--------
-
-This is a bugfix release with the following changes:
-
-* Fix include directory ordering when using bundled dependencies.
-
-* Fix infinite loop when searching for a non-existing repository with
- Windows-style paths including drive prefixes.
-
-* Fix paths with a trailing "/" not always being treated as
- directories when computing ignores.
-
-* Fix false negatives when computing ignores where ignore rules
- that are a prefix to a negative ignore rule exist.
-
-* Fix patches with CRLF line endings not being parsed correctly.
-
-* Fix segfault when parsing patches with file addition (deletion)
- where the added (deleted) file name contains a space.
-
-* Fix assertion failure when trying to write to a non-existent
- locked configuration file.
-
-v0.28.1
--------
-
-This is a bugfix release with the following change:
+### Breaking API changes
-* The deprecated functions (`git_buf_free` and the `giterr_` family of
- functions) are now exported properly. In the v0.28 release, they were
- not given the correct external attributes and they did not have the
- correct linkage visibility in the v0.28 library.
+* The "private" implementation details of the `git_cred` structure have been
+ moved to a dedicated `git2/sys/cred.h` header, to clarify that the underlying
+ structures are only provided for custom transport implementers.
+ The breaking change is that the `username` member of the underlying struct
+ is now hidden, and a new `git_cred_get_username` function has been provided.
+
+### Breaking CMake configuration changes
+
+* The CMake option to use a system http-parser library, instead of the
+ bundled dependency, has changed. This is due to a deficiency in
+ http-parser that we have fixed in our implementation. The bundled
+ library is now the default, but if you wish to force the use of the
+ system http-parser implementation despite incompatibilities, you can
+ specify `-DUSE_HTTP_PARSER=system` to CMake.
+
+* The interactions between `USE_HTTPS` and `SHA1_BACKEND` have been
+ streamlined. The detection was moved to a new `USE_SHA1`, modeled after
+ `USE_HTTPS`, which takes the values "CollisionDetection/Backend/Generic", to
+ better match how the "hashing backend" is selected, the default (ON) being
+ "CollisionDetection". If you were using `SHA1_BACKEND` previously, you'll
+ need to check the value you've used, or switch to the autodetection.
+
+### Authors
+
+The following individuals provided changes that were included in this
+release:
+
+* Aaron Patterson
+* Alberto Fanjul
+* Anders Borum
+* Augie Fackler
+* Augustin Fabre
+* Ayush Shridhar
+* brian m. carlson
+* buddyspike
+* Carlos Martín Nieto
+* cheese1
+* Dan Skorupski
+* Daniel Cohen Gindi
+* Dave Lee
+* David Brooks
+* David Turner
+* Denis Laxalde
+* Dhruva Krishnamurthy
+* Dominik Ritter
+* Drew DeVault
+* Edward Thomson
+* Eric Huss
+* Erik Aigner
+* Etienne Samson
+* Gregory Herrero
+* Heiko Voigt
+* Ian Hattendorf
+* Jacques Germishuys
+* Janardhan Pulivarthi
+* Jason Haslam
+* Johannes Schindelin
+* Jordan Wallet
+* Josh Bleecher Snyder
+* kas
+* kdj0c
+* Laurence McGlashan
+* lhchavez
+* Lukas Berk
+* Max Kostyukevich
+* Patrick Steinhardt
+* pcpthm
+* Remy Suen
+* Robert Coup
+* romkatv
+* Scott Furry
+* Sebastian Henke
+* Stefan Widgren
+* Steve King Jr
+* Sven Strickroth
+* Tobias Nießen
+* Tyler Ang-Wanek
+* Tyler Wanek
v0.28
-----
--- /dev/null
+# libgit2 Coding Style
+
+This documentation describes the preferred coding style for the libgit2 project.
+While not all parts of our code base conform to this coding style, the outlined
+rules are what we aim for.
+
+Note that in no case do we accept changes that convert huge parts of the code
+base to use our coding style. Instead, it is encouraged to modernize small parts
+of code you're going to modify anyway for a given change you want to introduce.
+A good rule to follow is the Boy Scout Rule: "Leave the campground cleaner than
+you found it."
+
+## C Coding Style
+
+The following sections define the coding style for all code files and headers.
+
+### Indentation and Alignment
+
+Code is indented by tabs, where a tab is 8 spaces. Each opening scope increases
+the indentation level.
+
+```c
+int foobar(int void)
+{
+ if (condition)
+ doit();
+ /* Body */
+}
+```
+
+Switch statements have their `case`s aligned with the `switch` keyword. Case
+bodies are indented by an additional level. Case bodies should not open their
+own scope to declare variables.
+
+```c
+switch (c) {
+case 'a':
+case 'b':
+ return 0;
+default:
+ return -1;
+}
+```
+
+Multi-line conditions should be aligned with the opening brace of the current
+statement:
+
+```c
+if (one_very_long_condition(c) &&
+ another_very_long_condition(c))
+ doit();
+```
+
+### Spaces
+
+There must be no space between the function and its arguments, arguments must be
+separated by a space:
+
+```c
+int doit(int first_arg, int second_arg);
+doit(1, 2);
+```
+
+For any binary or ternary operators, the arguments and separator must be
+separated by a space:
+
+```c
+1 + 2;
+x ? x : NULL;
+```
+
+Unary operators do not have a space between them and the argument they refer to:
+
+```c
+*c
+&c
+```
+
+The `sizeof` operator always must not have a space and must use braces around
+the type:
+
+```
+sizeof(int)
+```
+
+There must be a space after the keywords `if`, `switch`, `case`, `do` and
+`while`.
+
+### Braces
+
+Functions must have their opening brace on the following line:
+
+```c
+void foobar(void)
+{
+ doit();
+}
+```
+
+For conditions, braces should be placed on the same line as the condition:
+
+```c
+if (condition(c)) {
+ doit();
+ dothat();
+}
+
+while (true) {
+ doit();
+}
+```
+
+In case a condition's body has a single line, only, it's allowed to omit braces,
+except if any of its `else if` or `else` branches has more than one line:
+
+```c
+if (condition(c))
+ doit();
+
+if (condition(c))
+ doit();
+else if (other_condition(c))
+ doit();
+
+/* This example must use braces as the `else if` requires them. */
+if (condition(c)) {
+ doit();
+} else if (other_condition(c)) {
+ doit();
+ dothat();
+} else {
+ abort();
+}
+```
+
+### Comments
+
+Comments must use C-style `/* */` comments. C++-style `// `comments are not
+allowed in our codebase. This is a strict requirement as libgit2 tries to be
+compliant with the ISO C90 standard, which only allows C-style comments.
+
+Single-line comments may have their opening and closing tag on the same line:
+
+```c
+/* This is a short comment. */
+```
+
+For multi-line comments, the opening and closing tag should be empty:
+
+```c
+/*
+ * This is a rather long and potentially really unwiedly but informative
+ * multiline comment that helps quite a lot.
+ */
+```
+
+Public functions must have documentation that explain their usage, internal
+functions should have a comment. We use Docurium to generate documentation
+derived from these comments, which uses syntax similar to Doxygen. The first
+line should be a short summary of what the function does. More in-depth
+explanation should be separated from that first line by an empty line.
+Parameters and return values should be documented via `@return` and `@param`
+tags:
+
+```c
+/*
+ * Froznicate the string.
+ *
+ * Froznicate the string by foobaring its internal structure into a more obvious
+ * translation. Note that the returned string is a newly allocated string that
+ * shall be `free`d by the caller.
+ *
+ * @param s String to froznicate
+ * @return A newly allocated string or `NULL` in case an error occurred.
+ * /
+char *froznicate(const char *s);
+```
+
+### Variables
+
+Variables must be declared at the beginning of their scope. This is a strict
+requirement as libgit2 tries to be compliant with the ISO C90 standard, which
+forbids mixed declarations and code:
+
+```c
+void foobar(void)
+{
+ char *c = NULL;
+ int a, b;
+
+ a = 0;
+ b = 1;
+
+ return c;
+}
+```
+
+### Naming
+
+Variables must have all-lowercase names. In case a variable name has multiple
+words, words should be separated by an underscore `_` character. While
+recommended to use descriptive naming, common variable names like `i` for
+indices are allowed.
+
+All public functions must have a `git` prefix as well as a prefix indicating
+their respective subsystem. E.g. a function that opens a repository should be
+called `git_repository_open()`. Functions that are not public but declared in
+an internal header file for use by other subsystems should follow the same
+naming pattern. File-local static functions must not have a `git` prefix, but
+should have a prefix indicating their respective subsystem.
+
+All structures declared in the libgit2 project must have a `typedef`, we do not
+use `struct type` variables. Type names follow the same schema as functions.
+
+### Error Handling
+
+The libgit2 project mostly uses error codes to indicate errors. Error codes are
+always of type `int`, where `0` indicates success and a negative error code
+indicates an error case. In some cases, positive error codes may be used to
+indicate special cases. Returned values that are not an error code should be
+returned via an out parameter. Out parameters must always come first in the list
+of arguments.
+
+```c
+int doit(const char **out, int arg)
+{
+ if (!arg)
+ return -1;
+ *out = "Got an argument";
+ return 0;
+}
+```
+
+To avoid repetitive and fragile error handling in case a function has resources
+that need to be free'd, we use `goto out`s:
+
+```c
+int doit(char **out, int arg)
+{
+ int error = 0;
+ char *c;
+
+ c = malloc(strlen("Got an argument") + 1);
+ if (!c) {
+ error = -1;
+ goto out;
+ }
+
+ if (!arg) {
+ error = -1;
+ goto out;
+ }
+
+ strcpy(c, "Got an argument")
+ *out = c;
+
+out:
+ if (error)
+ free(c);
+ return error;
+}
+```
+
+When calling functions that return an error code, you should assign the error
+code to an `error` variable and, in case an error case is indicated and no
+custom error handling is required, return that error code:
+
+```c
+int foobar(void)
+{
+ int error;
+
+ if ((error = doit()) < 0)
+ return error;
+
+ return 0;
+}
+```
+
+When doing multiple function calls where all of the functions return an error
+code, it's common practice to chain these calls together:
+
+```c
+int doit(void)
+{
+ int error;
+
+ if ((error = dothis()) < 0 ||
+ (error = dothat()) < 0)
+ return error;
+
+ return 0;
+}
+```
+
+## CMake Coding Style
+
+The following section defines the coding style for our CMake build system.
+
+### Indentation
+
+Code is indented by tabs, where a tab is 8 spaces. Each opening scope increases
+the indentation level.
+
+```cmake
+if(CONDITION)
+ doit()
+endif()
+```
+
+### Spaces
+
+There must be no space between keywords and their opening brace. While this is
+the same as in our C codebase for function calls, this also applies to
+conditional keywords. This is done to avoid the awkward-looking `else ()`
+statement.
+
+```cmake
+if(CONDITION)
+ doit()
+else()
+ dothat()
+endif()
+```
+
+### Case
+
+While CMake is completely case-insensitive when it comes to function calls, we
+want to agree on a common coding style for this. To reduce the danger of
+repetitive strain injuries, all function calls should be lower-case (NB: this is
+not currently the case yet, but introduced as a new coding style by this
+document).
+
+Variables are written all-uppercase. In contrast to functions, variables are
+case-sensitive in CMake. As CMake itself uses upper-case variables in all
+places, we should follow suit and do the same.
+
+Control flow keywords must be all lowercase. In contrast to that, test keywords
+must be all uppercase:
+
+```cmake
+if(NOT CONDITION)
+ doit()
+elseif(FOO AND BAR)
+ dothat()
+endif()
+```
+
+### Targets
+
+CMake code should not use functions that modify the global scope but prefer
+their targeted equivalents, instead. E.g. instead of using
+`include_directories()`, you must use `target_include_directories()`. An
+exception to this rule is setting up global compiler flags like warnings or
+flags required to set up the build type.
+
+### Dependencies
+
+Dependencies should not be discovered or set up in the main "CMakeLists.txt"
+module. Instead, they should either have their own module in our top-level
+"cmake/" directory or have a "CMakeLists.txt" in their respective "deps/"
+directory in case it is a vendored library. All dependencies should expose
+interface library targets that can be linked against with
+`target_link_libraries()`.
libgit2 is currently using [libFuzzer](https://libfuzzer.info) to perform
automated fuzz testing. libFuzzer only works with clang.
-## Prerequisites** for building fuzz targets:
+## Prerequisites for building fuzz targets:
1. All the prerequisites for [building libgit2](https://github.com/libgit2/libgit2).
2. A recent version of clang. 6.0 is preferred. [pre-build Debian/Ubuntu
## Run the fuzz targets
-1. `ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolize-6.0
+1. `ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolize
LSAN_OPTIONS=allocator_may_return_null=1
- ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzz/fuzz_packfile_raw
- fuzz/corpora/fuzz_packfile_raw/`
+ ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzzers/packfile_fuzzer
+ fuzzers/corpora/packfile/`
The `LSAN_OPTIONS` and `ASAN_OPTIONS` are there to allow `malloc(3)` to return
-`NULL`. The `LLVM_PROFILE_FILE` is there to override the path where libFuzzer
-will write the coverage report.
+`NULL`, which is expected if a huge chunk of memory is allocated. The
+`LLVM_PROFILE_FILE` environment string can also be added to override the path
+where libFuzzer will write the coverage report.
## Get coverage
This is the same as a maintenance release, except that the fix itself will most likely be developed in a private repository and will only be visible to a select group of people until the release.
-Everything else remains the same. Occasionally we might opt to backport a security fix to the previous series, based on how recently we started the new series and how serious the issue is.
+We have committed to providing security fixes for the latest two released versions. E.g. if the latest version is v0.28.x, then we will provide security fixes for both v0.28.x and v0.27.y.
## Updating documentation
-Threads in libgit2
+Threading in libgit2
==================
-You may safely use any libgit2 object from any thread, though there
-may be issues depending on the cryptographic libraries libgit2 or its
+Unless otherwise specified, libgit2 objects cannot be safely accessed by
+multiple threads simultaneously.
+
+There are also caveats on the cryptographic libraries libgit2 or its
dependencies link to (more on this later). For libgit2 itself,
provided you take the following into consideration you won't run into
issues:
happen on the same thread as the error in order to get the
message. Often this will be the case regardless, but if you use
something like the [GCD](http://en.wikipedia.org/wiki/Grand_Central_Dispatch)
-on Mac OS X (where code is executed on an arbitrary thread), the code
+on macOS (where code is executed on an arbitrary thread), the code
must make sure to retrieve the error code on the thread where the error
happened.
-Threads and cryptographic libraries
+Threading and cryptographic libraries
=======================================
On Windows
libssh2 uses OpenSSL or libgcrypt, then the general case affects
you.
-On Mac OS X
+On macOS
-----------
-By default we use libcurl to perform the encryption. The
-system-provided libcurl uses SecureTransport, so no special steps are
-necessary. If you link against another libcurl (e.g. from homebrew)
-refer to the general case.
-
-If the option to use libcurl was deactivated, the library makes use of
-CommonCrypto and SecureTransport for cryptographic support. These are
-thread-safe and you do not need to do anything special.
+By default we make use of CommonCrypto and SecureTransport for cryptographic
+support. These are thread-safe and you do not need to do anything special.
Note that libssh2 may still use OpenSSL itself. In that case, the
general case still affects you if you use ssh.
General Case
------------
-If it's available, by default we use libcurl to provide HTTP tunneling support,
-which may be linked against a number of cryptographic libraries and has its
-own
-[recommendations for thread safety](https://curl.haxx.se/libcurl/c/threadsafe.html).
-
-If there are no alternative TLS implementations (currently only
-SecureTransport), libgit2 uses OpenSSL in order to use HTTPS as a transport.
-OpenSSL is thread-safe starting at version 1.1.0. If your copy of libgit2 is
-linked against that version, you do not need to take any further steps.
+libgit2 will default to OpenSSL for HTTPS transport (except on Windows and
+macOS, as mentioned above). On any system, mbedTLS _may_ be optionally
+enabled as the security provider. OpenSSL is thread-safe starting at
+version 1.1.0. If your copy of libgit2 is linked against that version,
+you do not need to take any further steps.
Older versions of OpenSSL are made to be thread-implementation agnostic, and the
users of the library must set which locking function it should use. libgit2
the locking settings must then live outside the lifetime of libgit2.
Even if libgit2 doesn't use OpenSSL directly, OpenSSL can still be used by
-libssh2 or libcurl depending on the configuration. If OpenSSL is used by
+libssh2 depending on the configuration. If OpenSSL is used by
more than one library, you only need to set up threading for OpenSSL once.
-If libgit2 is linked against OpenSSL, it provides a last-resort convenience function
+If libgit2 is linked against OpenSSL < 1.1.0, it provides a last-resort convenience function
`git_openssl_set_locking()` (available in `sys/openssl.h`) to use the
platform-native mutex mechanisms to perform the locking, which you can use
if you do not want to use OpenSSL outside of libgit2, or you
safe to use OpenSSL multi-threaded after libgit2's shutdown function
has been called. Note `git_openssl_set_locking()` only works if
libgit2 uses OpenSSL directly - if OpenSSL is only used as a dependency
-of libssh2 or libcurl as described above, `git_openssl_set_locking()` is a no-op.
+of libssh2 as described above, `git_openssl_set_locking()` is a no-op.
If your programming language offers a package/bindings for OpenSSL,
you should very strongly prefer to use that in order to set up
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES})
-FILE(GLOB_RECURSE SRC_EXAMPLE_GIT2 network/*.c network/*.h common.?)
-ADD_EXECUTABLE(cgit2 ${SRC_EXAMPLE_GIT2})
-SET_TARGET_PROPERTIES(cgit2 PROPERTIES C_STANDARD 90)
+FILE(GLOB LG2_SOURCES *.c *.h)
+ADD_EXECUTABLE(lg2 ${LG2_SOURCES})
+SET_TARGET_PROPERTIES(lg2 PROPERTIES C_STANDARD 90)
# Ensure that we do not use deprecated functions internally
ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD)
IF(WIN32 OR ANDROID)
- TARGET_LINK_LIBRARIES(cgit2 git2)
+ TARGET_LINK_LIBRARIES(lg2 git2)
ELSE()
- TARGET_LINK_LIBRARIES(cgit2 git2 pthread)
+ TARGET_LINK_LIBRARIES(lg2 git2 pthread)
ENDIF()
-
-FILE(GLOB SRC_EXAMPLE_APPS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c)
-FOREACH(src_app ${SRC_EXAMPLE_APPS})
- STRING(REPLACE ".c" "" app_name ${src_app})
- IF(NOT ${app_name} STREQUAL "common")
- ADD_EXECUTABLE(${app_name} ${src_app} "common.c")
- TARGET_LINK_LIBRARIES(${app_name} git2)
- SET_TARGET_PROPERTIES(${app_name} PROPERTIES C_STANDARD 90)
- ENDIF()
-ENDFOREACH()
*/
#include "common.h"
-#include <assert.h>
-enum print_options {
- SKIP = 1,
- VERBOSE = 2,
- UPDATE = 4,
+/**
+ * The following example demonstrates how to add files with libgit2.
+ *
+ * It will use the repository in the current working directory, and act
+ * on files passed as its parameters.
+ *
+ * Recognized options are:
+ * -v/--verbose: show the file's status after acting on it.
+ * -n/--dry-run: do not actually change the index.
+ * -u/--update: update the index instead of adding to it.
+ */
+
+enum index_mode {
+ INDEX_NONE,
+ INDEX_ADD,
};
-struct print_payload {
- enum print_options options;
+struct index_options {
+ int dry_run;
+ int verbose;
git_repository *repo;
+ enum index_mode mode;
+ int add_update;
};
/* Forward declarations for helpers */
-static void parse_opts(int *options, int *count, int argc, char *argv[]);
-void init_array(git_strarray *array, int argc, char **argv);
+static void parse_opts(const char **repo_path, struct index_options *opts, struct args_info *args);
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload);
-int main (int argc, char** argv)
+int lg2_add(git_repository *repo, int argc, char **argv)
{
git_index_matched_path_cb matched_cb = NULL;
- git_repository *repo = NULL;
git_index *index;
git_strarray array = {0};
- int options = 0, count = 0;
- struct print_payload payload = {0};
-
- git_libgit2_init();
+ struct index_options options = {0};
+ struct args_info args = ARGS_INFO_INIT;
- parse_opts(&options, &count, argc, argv);
+ options.mode = INDEX_ADD;
- init_array(&array, argc-count, argv+count);
+ /* Parse the options & arguments. */
+ parse_opts(NULL, &options, &args);
+ strarray_from_args(&array, &args);
- check_lg2(git_repository_open(&repo, "."), "No git repository", NULL);
+ /* Grab the repository's index. */
check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);
- if (options&VERBOSE || options&SKIP) {
+ /* Setup a callback if the requested options need it */
+ if (options.verbose || options.dry_run) {
matched_cb = &print_matched_cb;
}
- payload.options = options;
- payload.repo = repo;
+ options.repo = repo;
- if (options&UPDATE) {
- git_index_update_all(index, &array, matched_cb, &payload);
+ /* Perform the requested action with the index and files */
+ if (options.add_update) {
+ git_index_update_all(index, &array, matched_cb, &options);
} else {
- git_index_add_all(index, &array, 0, matched_cb, &payload);
+ git_index_add_all(index, &array, 0, matched_cb, &options);
}
+ /* Cleanup memory */
git_index_write(index);
git_index_free(index);
- git_repository_free(repo);
-
- git_libgit2_shutdown();
return 0;
}
+/*
+ * This callback is called for each file under consideration by
+ * git_index_(update|add)_all above.
+ * It makes uses of the callback's ability to abort the action.
+ */
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload)
{
- struct print_payload p = *(struct print_payload*)(payload);
+ struct index_options *opts = (struct index_options *)(payload);
int ret;
unsigned status;
(void)matched_pathspec;
- if (git_status_file(&status, p.repo, path)) {
+ /* Get the file status */
+ if (git_status_file(&status, opts->repo, path) < 0)
return -1;
- }
- if (status & GIT_STATUS_WT_MODIFIED || status & GIT_STATUS_WT_NEW) {
+ if ((status & GIT_STATUS_WT_MODIFIED) || (status & GIT_STATUS_WT_NEW)) {
printf("add '%s'\n", path);
ret = 0;
} else {
ret = 1;
}
- if(p.options & SKIP) {
+ if (opts->dry_run)
ret = 1;
- }
return ret;
}
unsigned int i;
array->count = argc;
- array->strings = malloc(sizeof(char*) * array->count);
- assert(array->strings!=NULL);
+ array->strings = calloc(array->count, sizeof(char *));
+ assert(array->strings != NULL);
- for(i=0; i<array->count; i++) {
- array->strings[i]=argv[i];
+ for (i = 0; i < array->count; i++) {
+ array->strings[i] = argv[i];
}
return;
exit(1);
}
-static void parse_opts(int *options, int *count, int argc, char *argv[])
+static void parse_opts(const char **repo_path, struct index_options *opts, struct args_info *args)
{
- int i;
+ if (args->argc <= 1)
+ print_usage();
- for (i = 1; i < argc; ++i) {
- if (argv[i][0] != '-') {
- break;
- }
- else if(!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v")) {
- *options |= VERBOSE;
- }
- else if(!strcmp(argv[i], "--dry-run") || !strcmp(argv[i], "-n")) {
- *options |= SKIP;
- }
- else if(!strcmp(argv[i], "--update") || !strcmp(argv[i], "-u")) {
- *options |= UPDATE;
- }
- else if(!strcmp(argv[i], "-h")) {
+ for (args->pos = 1; args->pos < args->argc; ++args->pos) {
+ const char *curr = args->argv[args->pos];
+
+ if (curr[0] != '-') {
+ if (!strcmp("add", curr)) {
+ opts->mode = INDEX_ADD;
+ continue;
+ } else if (opts->mode == INDEX_NONE) {
+ fprintf(stderr, "missing command: %s", curr);
+ print_usage();
+ break;
+ } else {
+ /* We might be looking at a filename */
+ break;
+ }
+ } else if (match_bool_arg(&opts->verbose, args, "--verbose") ||
+ match_bool_arg(&opts->dry_run, args, "--dry-run") ||
+ match_str_arg(repo_path, args, "--git-dir") ||
+ (opts->mode == INDEX_ADD && match_bool_arg(&opts->add_update, args, "--update"))) {
+ continue;
+ } else if (match_bool_arg(NULL, args, "--help")) {
print_usage();
break;
- }
- else if(!strcmp(argv[i], "--")) {
- i++;
+ } else if (match_arg_separator(args)) {
break;
- }
- else {
- fprintf(stderr, "Unsupported option %s.\n", argv[i]);
+ } else {
+ fprintf(stderr, "Unsupported option %s.\n", curr);
print_usage();
}
}
-
- if (argc<=i)
- print_usage();
-
- *count = i;
}
--- /dev/null
+#include "common.h"
+#include "args.h"
+
+size_t is_prefixed(const char *str, const char *pfx)
+{
+ size_t len = strlen(pfx);
+ return strncmp(str, pfx, len) ? 0 : len;
+}
+
+int optional_str_arg(
+ const char **out, struct args_info *args, const char *opt, const char *def)
+{
+ const char *found = args->argv[args->pos];
+ size_t len = is_prefixed(found, opt);
+
+ if (!len)
+ return 0;
+
+ if (!found[len]) {
+ if (args->pos + 1 == args->argc) {
+ *out = def;
+ return 1;
+ }
+ args->pos += 1;
+ *out = args->argv[args->pos];
+ return 1;
+ }
+
+ if (found[len] == '=') {
+ *out = found + len + 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+int match_str_arg(
+ const char **out, struct args_info *args, const char *opt)
+{
+ const char *found = args->argv[args->pos];
+ size_t len = is_prefixed(found, opt);
+
+ if (!len)
+ return 0;
+
+ if (!found[len]) {
+ if (args->pos + 1 == args->argc)
+ fatal("expected value following argument", opt);
+ args->pos += 1;
+ *out = args->argv[args->pos];
+ return 1;
+ }
+
+ if (found[len] == '=') {
+ *out = found + len + 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static const char *match_numeric_arg(struct args_info *args, const char *opt)
+{
+ const char *found = args->argv[args->pos];
+ size_t len = is_prefixed(found, opt);
+
+ if (!len)
+ return NULL;
+
+ if (!found[len]) {
+ if (args->pos + 1 == args->argc)
+ fatal("expected numeric value following argument", opt);
+ args->pos += 1;
+ found = args->argv[args->pos];
+ } else {
+ found = found + len;
+ if (*found == '=')
+ found++;
+ }
+
+ return found;
+}
+
+int match_uint16_arg(
+ uint16_t *out, struct args_info *args, const char *opt)
+{
+ const char *found = match_numeric_arg(args, opt);
+ uint16_t val;
+ char *endptr = NULL;
+
+ if (!found)
+ return 0;
+
+ val = (uint16_t)strtoul(found, &endptr, 0);
+ if (!endptr || *endptr != '\0')
+ fatal("expected number after argument", opt);
+
+ if (out)
+ *out = val;
+ return 1;
+}
+
+int match_uint32_arg(
+ uint32_t *out, struct args_info *args, const char *opt)
+{
+ const char *found = match_numeric_arg(args, opt);
+ uint16_t val;
+ char *endptr = NULL;
+
+ if (!found)
+ return 0;
+
+ val = (uint32_t)strtoul(found, &endptr, 0);
+ if (!endptr || *endptr != '\0')
+ fatal("expected number after argument", opt);
+
+ if (out)
+ *out = val;
+ return 1;
+}
+
+static int match_int_internal(
+ int *out, const char *str, int allow_negative, const char *opt)
+{
+ char *endptr = NULL;
+ int val = (int)strtol(str, &endptr, 10);
+
+ if (!endptr || *endptr != '\0')
+ fatal("expected number", opt);
+ else if (val < 0 && !allow_negative)
+ fatal("negative values are not allowed", opt);
+
+ if (out)
+ *out = val;
+
+ return 1;
+}
+
+int match_bool_arg(int *out, struct args_info *args, const char *opt)
+{
+ const char *found = args->argv[args->pos];
+
+ if (!strcmp(found, opt)) {
+ *out = 1;
+ return 1;
+ }
+
+ if (!strncmp(found, "--no-", strlen("--no-")) &&
+ !strcmp(found + strlen("--no-"), opt + 2)) {
+ *out = 0;
+ return 1;
+ }
+
+ *out = -1;
+ return 0;
+}
+
+int is_integer(int *out, const char *str, int allow_negative)
+{
+ return match_int_internal(out, str, allow_negative, NULL);
+}
+
+int match_int_arg(
+ int *out, struct args_info *args, const char *opt, int allow_negative)
+{
+ const char *found = match_numeric_arg(args, opt);
+ if (!found)
+ return 0;
+ return match_int_internal(out, found, allow_negative, opt);
+}
+
+int match_arg_separator(struct args_info *args)
+{
+ if (args->opts_done)
+ return 1;
+
+ if (strcmp(args->argv[args->pos], "--") != 0)
+ return 0;
+
+ args->opts_done = 1;
+ args->pos++;
+ return 1;
+}
+
+void strarray_from_args(git_strarray *array, struct args_info *args)
+{
+ size_t i;
+
+ array->count = args->argc - args->pos;
+ array->strings = calloc(array->count, sizeof(char *));
+ assert(array->strings != NULL);
+
+ for (i = 0; args->pos < args->argc; ++args->pos) {
+ array->strings[i++] = args->argv[args->pos];
+ }
+ args->pos = args->argc;
+}
--- /dev/null
+#ifndef INCLUDE_examples_args_h__
+#define INCLUDE_examples_args_h__
+
+/**
+ * Argument-processing helper structure
+ */
+struct args_info {
+ int argc;
+ char **argv;
+ int pos;
+ int opts_done : 1; /**< Did we see a -- separator */
+};
+#define ARGS_INFO_INIT { argc, argv, 0, 0 }
+#define ARGS_CURRENT(args) args->argv[args->pos]
+
+/**
+ * Check if a string has the given prefix. Returns 0 if not prefixed
+ * or the length of the prefix if it is.
+ */
+extern size_t is_prefixed(const char *str, const char *pfx);
+
+/**
+ * Match an integer string, returning 1 if matched, 0 if not.
+ */
+extern int is_integer(int *out, const char *str, int allow_negative);
+
+/**
+ * Check current `args` entry against `opt` string. If it matches
+ * exactly, take the next arg as a string; if it matches as a prefix with
+ * an equal sign, take the remainder as a string; if value not supplied,
+ * default value `def` will be given. otherwise return 0.
+ */
+extern int optional_str_arg(
+ const char **out, struct args_info *args, const char *opt, const char *def);
+
+/**
+ * Check current `args` entry against `opt` string. If it matches
+ * exactly, take the next arg as a string; if it matches as a prefix with
+ * an equal sign, take the remainder as a string; otherwise return 0.
+ */
+extern int match_str_arg(
+ const char **out, struct args_info *args, const char *opt);
+
+/**
+ * Check current `args` entry against `opt` string parsing as uint16. If
+ * `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
+ * is a prefix (equal sign optional), take the remainder of the arg as a
+ * uint16_t value; otherwise return 0.
+ */
+extern int match_uint16_arg(
+ uint16_t *out, struct args_info *args, const char *opt);
+
+/**
+ * Check current `args` entry against `opt` string parsing as uint32. If
+ * `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
+ * is a prefix (equal sign optional), take the remainder of the arg as a
+ * uint32_t value; otherwise return 0.
+ */
+extern int match_uint32_arg(
+ uint32_t *out, struct args_info *args, const char *opt);
+
+/**
+ * Check current `args` entry against `opt` string parsing as int. If
+ * `opt` matches exactly, take the next arg as an int value; if it matches
+ * as a prefix (equal sign optional), take the remainder of the arg as a
+ * int value; otherwise return 0.
+ */
+extern int match_int_arg(
+ int *out, struct args_info *args, const char *opt, int allow_negative);
+
+/**
+ * Check current `args` entry against a "bool" `opt` (ie. --[no-]progress).
+ * If `opt` matches positively, out will be set to 1, or if `opt` matches
+ * negatively, out will be set to 0, and in both cases 1 will be returned.
+ * If neither the positive or the negative form of opt matched, out will be -1,
+ * and 0 will be returned.
+ */
+extern int match_bool_arg(int *out, struct args_info *args, const char *opt);
+
+/**
+ * Check if we're processing past the single -- separator
+ */
+extern int match_arg_separator(struct args_info *args);
+
+/**
+ * Consume all remaining arguments in a git_strarray
+ */
+extern void strarray_from_args(git_strarray *array, struct args_info *args);
+
+#endif
#include "common.h"
-#ifdef _MSC_VER
-#define snprintf sprintf_s
-#define strcasecmp strcmpi
-#endif
-
/**
* This example demonstrates how to invoke the libgit2 blame API to roughly
* simulate the output of `git blame` and a few of its command line arguments.
*/
-struct opts {
+struct blame_opts {
char *path;
char *commitspec;
int C;
int end_line;
int F;
};
-static void parse_opts(struct opts *o, int argc, char *argv[]);
+static void parse_opts(struct blame_opts *o, int argc, char *argv[]);
-int main(int argc, char *argv[])
+int lg2_blame(git_repository *repo, int argc, char *argv[])
{
int line, break_on_null_hunk;
- size_t i, rawsize;
+ git_object_size_t i, rawsize;
char spec[1024] = {0};
- struct opts o = {0};
+ struct blame_opts o = {0};
const char *rawdata;
- git_repository *repo = NULL;
git_revspec revspec = {0};
git_blame_options blameopts = GIT_BLAME_OPTIONS_INIT;
git_blame *blame = NULL;
git_blob *blob;
git_object *obj;
- git_libgit2_init();
-
parse_opts(&o, argc, argv);
if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;
if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;
if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT;
- /** Open the repository. */
- check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "Couldn't open repository", NULL);
-
/**
* The commit range comes in "commitish" form. Use the rev-parse API to
* nail down the end points.
* Get the raw data inside the blob for output. We use the
* `commitish:path/to/file.txt` format to find it.
*/
- if (git_oid_iszero(&blameopts.newest_commit))
+ if (git_oid_is_zero(&blameopts.newest_commit))
strcpy(spec, "HEAD");
else
git_oid_tostr(spec, sizeof(spec), &blameopts.newest_commit);
i = 0;
break_on_null_hunk = 0;
while (i < rawsize) {
- const char *eol = memchr(rawdata + i, '\n', rawsize - i);
+ const char *eol = memchr(rawdata + i, '\n', (size_t)(rawsize - i));
char oid[10] = {0};
const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line);
if (hunk) {
char sig[128] = {0};
break_on_null_hunk = 1;
-
+
git_oid_tostr(oid, 10, &hunk->final_commit_id);
snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email);
/** Cleanup. */
git_blob_free(blob);
git_blame_free(blame);
- git_repository_free(repo);
-
- git_libgit2_shutdown();
return 0;
}
}
/** Parse the arguments. */
-static void parse_opts(struct opts *o, int argc, char *argv[])
+static void parse_opts(struct blame_opts *o, int argc, char *argv[])
{
int i;
char *bare_args[3] = {0};
printf("\n%s\n", git_tag_message(tag));
}
-enum {
+typedef enum {
SHOW_TYPE = 1,
SHOW_SIZE = 2,
SHOW_NONE = 3,
SHOW_PRETTY = 4
-};
+} catfile_mode;
/* Forward declarations for option-parsing helper */
-struct opts {
+struct catfile_options {
const char *dir;
const char *rev;
- int action;
+ catfile_mode action;
int verbose;
};
-static void parse_opts(struct opts *o, int argc, char *argv[]);
+
+static void parse_opts(struct catfile_options *o, int argc, char *argv[]);
/** Entry point for this command */
-int main(int argc, char *argv[])
+int lg2_cat_file(git_repository *repo, int argc, char *argv[])
{
- git_repository *repo;
- struct opts o = { ".", NULL, 0, 0 };
+ struct catfile_options o = { ".", NULL, 0, 0 };
git_object *obj = NULL;
char oidstr[GIT_OID_HEXSZ + 1];
- git_libgit2_init();
-
parse_opts(&o, argc, argv);
- check_lg2(git_repository_open_ext(&repo, o.dir, 0, NULL),
- "Could not open repository", NULL);
check_lg2(git_revparse_single(&obj, repo, o.rev),
"Could not resolve", o.rev);
}
git_object_free(obj);
- git_repository_free(repo);
-
- git_libgit2_shutdown();
return 0;
}
}
/** Parse the command-line options taken from git */
-static void parse_opts(struct opts *o, int argc, char *argv[])
+static void parse_opts(struct catfile_options *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
*/
#include "common.h"
-#include <assert.h>
/* Define the printf format specifer to use for size_t output */
#if defined(_MSC_VER) || defined(__MINGW32__)
const char *curr = args->argv[args->pos];
int bool_arg;
- if (strcmp(curr, "--") == 0) {
+ if (match_arg_separator(args)) {
break;
} else if (!strcmp(curr, "--force")) {
opts->force = 1;
* This is the main "checkout <branch>" function, responsible for performing
* a branch-based checkout.
*/
-static int perform_checkout_ref(git_repository *repo, git_annotated_commit *target, checkout_options *opts)
+static int perform_checkout_ref(git_repository *repo, git_annotated_commit *target, const char *target_ref, checkout_options *opts)
{
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_reference *ref = NULL, *branch = NULL;
git_commit *target_commit = NULL;
int err;
* we might need to detach HEAD.
*/
if (git_annotated_commit_ref(target)) {
- err = git_repository_set_head(repo, git_annotated_commit_ref(target));
+ const char *target_head;
+
+ if ((err = git_reference_lookup(&ref, repo, git_annotated_commit_ref(target))) < 0)
+ goto error;
+
+ if (git_reference_is_remote(ref)) {
+ if ((err = git_branch_create_from_annotated(&branch, repo, target_ref, target, 0)) < 0)
+ goto error;
+ target_head = git_reference_name(branch);
+ } else {
+ target_head = git_annotated_commit_ref(target);
+ }
+
+ err = git_repository_set_head(repo, target_head);
} else {
err = git_repository_set_head_detached_from_annotated(repo, target);
}
+
+error:
if (err != 0) {
fprintf(stderr, "failed to update HEAD reference: %s\n", git_error_last()->message);
goto cleanup;
cleanup:
git_commit_free(target_commit);
+ git_reference_free(branch);
+ git_reference_free(ref);
return err;
}
+/**
+ * This corresponds to `git switch --guess`: if a given ref does
+ * not exist, git will by default try to guess the reference by
+ * seeing whether any remote has a branch called <ref>. If there
+ * is a single remote only that has it, then it is assumed to be
+ * the desired reference and a local branch is created for it.
+ *
+ * The following is a simplified implementation. It will not try
+ * to check whether the ref is unique across all remotes.
+ */
+static int guess_refish(git_annotated_commit **out, git_repository *repo, const char *ref)
+{
+ git_strarray remotes = { NULL, 0 };
+ git_reference *remote_ref = NULL;
+ int error;
+ size_t i;
+
+ if ((error = git_remote_list(&remotes, repo)) < 0)
+ goto out;
+
+ for (i = 0; i < remotes.count; i++) {
+ char *refname = NULL;
+ size_t reflen;
+
+ reflen = snprintf(refname, 0, "refs/remotes/%s/%s", remotes.strings[i], ref);
+ if ((refname = malloc(reflen + 1)) == NULL) {
+ error = -1;
+ goto next;
+ }
+ snprintf(refname, reflen + 1, "refs/remotes/%s/%s", remotes.strings[i], ref);
+
+ if ((error = git_reference_lookup(&remote_ref, repo, refname)) < 0)
+ goto next;
+
+ break;
+next:
+ free(refname);
+ if (error < 0 && error != GIT_ENOTFOUND)
+ break;
+ }
+
+ if (!remote_ref) {
+ error = GIT_ENOTFOUND;
+ goto out;
+ }
+
+ if ((error = git_annotated_commit_from_ref(out, repo, remote_ref)) < 0)
+ goto out;
+
+out:
+ git_reference_free(remote_ref);
+ git_strarray_dispose(&remotes);
+ return error;
+}
+
/** That example's entry point */
-int main(int argc, char **argv)
+int lg2_checkout(git_repository *repo, int argc, char **argv)
{
- git_repository *repo = NULL;
struct args_info args = ARGS_INFO_INIT;
checkout_options opts;
git_repository_state_t state;
/** Parse our command line options */
parse_options(&path, &opts, &args);
- /** Initialize the library */
- err = git_libgit2_init();
- if (!err)
- check_lg2(err, "Failed to initialize libgit2", NULL);
-
- /** Open the repository corresponding to the options */
- check_lg2(git_repository_open_ext(&repo, path, 0, NULL),
- "Could not open repository", NULL);
-
/** Make sure we're not about to checkout while something else is going on */
state = git_repository_state(repo);
if (state != GIT_REPOSITORY_STATE_NONE) {
goto cleanup;
}
- if (args.pos >= args.argc) {
- fprintf(stderr, "unhandled\n");
- err = -1;
- goto cleanup;
- } else if (strcmp("--", args.argv[args.pos])) {
+ if (match_arg_separator(&args)) {
/**
* Try to checkout the given path
*/
/**
* Try to resolve a "refish" argument to a target libgit2 can use
*/
- err = resolve_refish(&checkout_target, repo, args.argv[args.pos]);
- if (err != 0) {
+ if ((err = resolve_refish(&checkout_target, repo, args.argv[args.pos])) < 0 &&
+ (err = guess_refish(&checkout_target, repo, args.argv[args.pos])) < 0) {
fprintf(stderr, "failed to resolve %s: %s\n", args.argv[args.pos], git_error_last()->message);
goto cleanup;
}
- err = perform_checkout_ref(repo, checkout_target, &opts);
+ err = perform_checkout_ref(repo, checkout_target, args.argv[args.pos], &opts);
}
cleanup:
git_annotated_commit_free(checkout_target);
- git_repository_free(repo);
- git_libgit2_shutdown();
-
return err;
}
--- /dev/null
+#include "common.h"
+
+typedef struct progress_data {
+ git_indexer_progress fetch_progress;
+ size_t completed_steps;
+ size_t total_steps;
+ const char *path;
+} progress_data;
+
+static void print_progress(const progress_data *pd)
+{
+ int network_percent = pd->fetch_progress.total_objects > 0 ?
+ (100*pd->fetch_progress.received_objects) / pd->fetch_progress.total_objects :
+ 0;
+ int index_percent = pd->fetch_progress.total_objects > 0 ?
+ (100*pd->fetch_progress.indexed_objects) / pd->fetch_progress.total_objects :
+ 0;
+
+ int checkout_percent = pd->total_steps > 0
+ ? (int)((100 * pd->completed_steps) / pd->total_steps)
+ : 0;
+ size_t kbytes = pd->fetch_progress.received_bytes / 1024;
+
+ if (pd->fetch_progress.total_objects &&
+ pd->fetch_progress.received_objects == pd->fetch_progress.total_objects) {
+ printf("Resolving deltas %u/%u\r",
+ pd->fetch_progress.indexed_deltas,
+ pd->fetch_progress.total_deltas);
+ } else {
+ printf("net %3d%% (%4" PRIuZ " kb, %5u/%5u) / idx %3d%% (%5u/%5u) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ")%s\n",
+ network_percent, kbytes,
+ pd->fetch_progress.received_objects, pd->fetch_progress.total_objects,
+ index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects,
+ checkout_percent,
+ pd->completed_steps, pd->total_steps,
+ pd->path);
+ }
+}
+
+static int sideband_progress(const char *str, int len, void *payload)
+{
+ (void)payload; /* unused */
+
+ printf("remote: %.*s", len, str);
+ fflush(stdout);
+ return 0;
+}
+
+static int fetch_progress(const git_indexer_progress *stats, void *payload)
+{
+ progress_data *pd = (progress_data*)payload;
+ pd->fetch_progress = *stats;
+ print_progress(pd);
+ return 0;
+}
+static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload)
+{
+ progress_data *pd = (progress_data*)payload;
+ pd->completed_steps = cur;
+ pd->total_steps = tot;
+ pd->path = path;
+ print_progress(pd);
+}
+
+
+int lg2_clone(git_repository *repo, int argc, char **argv)
+{
+ progress_data pd = {{0}};
+ git_repository *cloned_repo = NULL;
+ git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
+ git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
+ const char *url = argv[1];
+ const char *path = argv[2];
+ int error;
+
+ (void)repo; /* unused */
+
+ /* Validate args */
+ if (argc < 3) {
+ printf ("USAGE: %s <url> <path>\n", argv[0]);
+ return -1;
+ }
+
+ /* Set up options */
+ checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
+ checkout_opts.progress_cb = checkout_progress;
+ checkout_opts.progress_payload = &pd;
+ clone_opts.checkout_opts = checkout_opts;
+ clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress;
+ clone_opts.fetch_opts.callbacks.transfer_progress = &fetch_progress;
+ clone_opts.fetch_opts.callbacks.credentials = cred_acquire_cb;
+ clone_opts.fetch_opts.callbacks.payload = &pd;
+
+ /* Do the clone */
+ error = git_clone(&cloned_repo, url, path, &clone_opts);
+ printf("\n");
+ if (error != 0) {
+ const git_error *err = git_error_last();
+ if (err) printf("ERROR %d: %s\n", err->klass, err->message);
+ else printf("ERROR %d: no detailed info\n", error);
+ }
+ else if (cloned_repo) git_repository_free(cloned_repo);
+ return error;
+}
--- /dev/null
+/*
+ * libgit2 "commit" example - shows how to create a git commit
+ *
+ * Written by the libgit2 contributors
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include "common.h"
+
+/**
+ * This example demonstrates the libgit2 commit APIs to roughly
+ * simulate `git commit` with the commit message argument.
+ *
+ * This does not have:
+ *
+ * - Robust error handling
+ * - Most of the `git commit` options
+ *
+ * This does have:
+ *
+ * - Example of performing a git commit with a comment
+ *
+ */
+int lg2_commit(git_repository *repo, int argc, char **argv)
+{
+ const char *opt = argv[1];
+ const char *comment = argv[2];
+ int error;
+
+ git_oid commit_oid,tree_oid;
+ git_tree *tree;
+ git_index *index;
+ git_object *parent = NULL;
+ git_reference *ref = NULL;
+ git_signature *signature;
+
+ /* Validate args */
+ if (argc < 3 || strcmp(opt, "-m") != 0) {
+ printf ("USAGE: %s -m <comment>\n", argv[0]);
+ return -1;
+ }
+
+ error = git_revparse_ext(&parent, &ref, repo, "HEAD");
+ if (error == GIT_ENOTFOUND) {
+ printf("HEAD not found. Creating first commit\n");
+ error = 0;
+ } else if (error != 0) {
+ const git_error *err = git_error_last();
+ if (err) printf("ERROR %d: %s\n", err->klass, err->message);
+ else printf("ERROR %d: no detailed info\n", error);
+ }
+
+ check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);
+ check_lg2(git_index_write_tree(&tree_oid, index), "Could not write tree", NULL);;
+ check_lg2(git_index_write(index), "Could not write index", NULL);;
+
+ check_lg2(git_tree_lookup(&tree, repo, &tree_oid), "Error looking up tree", NULL);
+
+ check_lg2(git_signature_default(&signature, repo), "Error creating signature", NULL);
+
+ check_lg2(git_commit_create_v(
+ &commit_oid,
+ repo,
+ "HEAD",
+ signature,
+ signature,
+ NULL,
+ comment,
+ tree,
+ parent ? 1 : 0, parent), "Error creating commit", NULL);
+
+ git_index_free(index);
+ git_signature_free(signature);
+ git_tree_free(tree);
+
+ return error;
+}
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <assert.h>
#include "common.h"
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+#include <errno.h>
+
void check_lg2(int error, const char *message, const char *extra)
{
const git_error *lg2err;
exit(1);
}
-size_t is_prefixed(const char *str, const char *pfx)
-{
- size_t len = strlen(pfx);
- return strncmp(str, pfx, len) ? 0 : len;
-}
-
-int optional_str_arg(
- const char **out, struct args_info *args, const char *opt, const char *def)
-{
- const char *found = args->argv[args->pos];
- size_t len = is_prefixed(found, opt);
-
- if (!len)
- return 0;
-
- if (!found[len]) {
- if (args->pos + 1 == args->argc) {
- *out = def;
- return 1;
- }
- args->pos += 1;
- *out = args->argv[args->pos];
- return 1;
- }
-
- if (found[len] == '=') {
- *out = found + len + 1;
- return 1;
- }
-
- return 0;
-}
-
-int match_str_arg(
- const char **out, struct args_info *args, const char *opt)
-{
- const char *found = args->argv[args->pos];
- size_t len = is_prefixed(found, opt);
-
- if (!len)
- return 0;
-
- if (!found[len]) {
- if (args->pos + 1 == args->argc)
- fatal("expected value following argument", opt);
- args->pos += 1;
- *out = args->argv[args->pos];
- return 1;
- }
-
- if (found[len] == '=') {
- *out = found + len + 1;
- return 1;
- }
-
- return 0;
-}
-
-static const char *match_numeric_arg(struct args_info *args, const char *opt)
-{
- const char *found = args->argv[args->pos];
- size_t len = is_prefixed(found, opt);
-
- if (!len)
- return NULL;
-
- if (!found[len]) {
- if (args->pos + 1 == args->argc)
- fatal("expected numeric value following argument", opt);
- args->pos += 1;
- found = args->argv[args->pos];
- } else {
- found = found + len;
- if (*found == '=')
- found++;
- }
-
- return found;
-}
-
-int match_uint16_arg(
- uint16_t *out, struct args_info *args, const char *opt)
-{
- const char *found = match_numeric_arg(args, opt);
- uint16_t val;
- char *endptr = NULL;
-
- if (!found)
- return 0;
-
- val = (uint16_t)strtoul(found, &endptr, 0);
- if (!endptr || *endptr != '\0')
- fatal("expected number after argument", opt);
-
- if (out)
- *out = val;
- return 1;
-}
-
-int match_uint32_arg(
- uint32_t *out, struct args_info *args, const char *opt)
-{
- const char *found = match_numeric_arg(args, opt);
- uint16_t val;
- char *endptr = NULL;
-
- if (!found)
- return 0;
-
- val = (uint32_t)strtoul(found, &endptr, 0);
- if (!endptr || *endptr != '\0')
- fatal("expected number after argument", opt);
-
- if (out)
- *out = val;
- return 1;
-}
-
-static int match_int_internal(
- int *out, const char *str, int allow_negative, const char *opt)
-{
- char *endptr = NULL;
- int val = (int)strtol(str, &endptr, 10);
-
- if (!endptr || *endptr != '\0')
- fatal("expected number", opt);
- else if (val < 0 && !allow_negative)
- fatal("negative values are not allowed", opt);
-
- if (out)
- *out = val;
-
- return 1;
-}
-
-int match_bool_arg(int *out, struct args_info *args, const char *opt)
-{
- const char *found = args->argv[args->pos];
-
- if (!strcmp(found, opt)) {
- *out = 1;
- return 1;
- }
-
- if (!strncmp(found, "--no-", strlen("--no-")) &&
- !strcmp(found + strlen("--no-"), opt + 2)) {
- *out = 0;
- return 1;
- }
-
- *out = -1;
- return 0;
-}
-
-int is_integer(int *out, const char *str, int allow_negative)
-{
- return match_int_internal(out, str, allow_negative, NULL);
-}
-
-int match_int_arg(
- int *out, struct args_info *args, const char *opt, int allow_negative)
-{
- const char *found = match_numeric_arg(args, opt);
- if (!found)
- return 0;
- return match_int_internal(out, found, allow_negative, opt);
-}
-
int diff_output(
const git_diff_delta *d,
const git_diff_hunk *h,
return err;
}
+
+static int readline(char **out)
+{
+ int c, error = 0, length = 0, allocated = 0;
+ char *line = NULL;
+
+ errno = 0;
+
+ while ((c = getchar()) != EOF) {
+ if (length == allocated) {
+ allocated += 16;
+
+ if ((line = realloc(line, allocated)) == NULL) {
+ error = -1;
+ goto error;
+ }
+ }
+
+ if (c == '\n')
+ break;
+
+ line[length++] = c;
+ }
+
+ if (errno != 0) {
+ error = -1;
+ goto error;
+ }
+
+ line[length] = '\0';
+ *out = line;
+ line = NULL;
+ error = length;
+error:
+ free(line);
+ return error;
+}
+
+static int ask(char **out, const char *prompt, char optional)
+{
+ printf("%s ", prompt);
+ fflush(stdout);
+
+ if (!readline(out) && !optional) {
+ fprintf(stderr, "Could not read response: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int cred_acquire_cb(git_credential **out,
+ const char *url,
+ const char *username_from_url,
+ unsigned int allowed_types,
+ void *payload)
+{
+ char *username = NULL, *password = NULL, *privkey = NULL, *pubkey = NULL;
+ int error = 1;
+
+ UNUSED(url);
+ UNUSED(payload);
+
+ if (username_from_url) {
+ if ((username = strdup(username_from_url)) == NULL)
+ goto out;
+ } else if ((error = ask(&username, "Username:", 0)) < 0) {
+ goto out;
+ }
+
+ if (allowed_types & GIT_CREDENTIAL_SSH_KEY) {
+ int n;
+
+ if ((error = ask(&privkey, "SSH Key:", 0)) < 0 ||
+ (error = ask(&password, "Password:", 1)) < 0)
+ goto out;
+
+ if ((n = snprintf(NULL, 0, "%s.pub", privkey)) < 0 ||
+ (pubkey = malloc(n + 1)) == NULL ||
+ (n = snprintf(pubkey, n + 1, "%s.pub", privkey)) < 0)
+ goto out;
+
+ error = git_credential_ssh_key_new(out, username, pubkey, privkey, password);
+ } else if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) {
+ if ((error = ask(&password, "Password:", 1)) < 0)
+ goto out;
+
+ error = git_credential_userpass_plaintext_new(out, username, password);
+ } else if (allowed_types & GIT_CREDENTIAL_USERNAME) {
+ error = git_credential_username_new(out, username);
+ }
+
+out:
+ free(username);
+ free(password);
+ free(privkey);
+ free(pubkey);
+ return error;
+}
+
+char *read_file(const char *path)
+{
+ ssize_t total = 0;
+ char *buf = NULL;
+ struct stat st;
+ int fd = -1;
+
+ if ((fd = open(path, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
+ goto out;
+
+ if ((buf = malloc(st.st_size + 1)) == NULL)
+ goto out;
+
+ while (total < st.st_size) {
+ ssize_t bytes = read(fd, buf + total, st.st_size - total);
+ if (bytes <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ free(buf);
+ buf = NULL;
+ goto out;
+ }
+ total += bytes;
+ }
+
+ buf[total] = '\0';
+
+out:
+ if (fd >= 0)
+ close(fd);
+ return buf;
+}
+
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
+#ifndef INCLUDE_examples_common_h__
+#define INCLUDE_examples_common_h__
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <git2.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+# include <io.h>
+# include <Windows.h>
+# define open _open
+# define read _read
+# define close _close
+# define ssize_t int
+# define sleep(a) Sleep(a * 1000)
+#else
+# include <unistd.h>
+#endif
+
+#ifndef PRIuZ
+/* Define the printf format specifer to use for size_t output */
+#if defined(_MSC_VER) || defined(__MINGW32__)
+# define PRIuZ "Iu"
+#else
+# define PRIuZ "zu"
+#endif
+#endif
+
+#ifdef _MSC_VER
+#define snprintf sprintf_s
+#define strcasecmp strcmpi
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
+#define UNUSED(x) (void)(x)
+
+#include "args.h"
+
+extern int lg2_add(git_repository *repo, int argc, char **argv);
+extern int lg2_blame(git_repository *repo, int argc, char **argv);
+extern int lg2_cat_file(git_repository *repo, int argc, char **argv);
+extern int lg2_checkout(git_repository *repo, int argc, char **argv);
+extern int lg2_clone(git_repository *repo, int argc, char **argv);
+extern int lg2_commit(git_repository *repo, int argc, char **argv);
+extern int lg2_config(git_repository *repo, int argc, char **argv);
+extern int lg2_describe(git_repository *repo, int argc, char **argv);
+extern int lg2_diff(git_repository *repo, int argc, char **argv);
+extern int lg2_fetch(git_repository *repo, int argc, char **argv);
+extern int lg2_for_each_ref(git_repository *repo, int argc, char **argv);
+extern int lg2_general(git_repository *repo, int argc, char **argv);
+extern int lg2_index_pack(git_repository *repo, int argc, char **argv);
+extern int lg2_init(git_repository *repo, int argc, char **argv);
+extern int lg2_log(git_repository *repo, int argc, char **argv);
+extern int lg2_ls_files(git_repository *repo, int argc, char **argv);
+extern int lg2_ls_remote(git_repository *repo, int argc, char **argv);
+extern int lg2_merge(git_repository *repo, int argc, char **argv);
+extern int lg2_push(git_repository *repo, int argc, char **argv);
+extern int lg2_remote(git_repository *repo, int argc, char **argv);
+extern int lg2_rev_list(git_repository *repo, int argc, char **argv);
+extern int lg2_rev_parse(git_repository *repo, int argc, char **argv);
+extern int lg2_show_index(git_repository *repo, int argc, char **argv);
+extern int lg2_stash(git_repository *repo, int argc, char **argv);
+extern int lg2_status(git_repository *repo, int argc, char **argv);
+extern int lg2_tag(git_repository *repo, int argc, char **argv);
/**
* Check libgit2 error code, printing error to stderr on failure and
extern void check_lg2(int error, const char *message, const char *extra);
/**
- * Exit the program, printing error to stderr
- */
-extern void fatal(const char *message, const char *extra);
-
-/**
- * Check if a string has the given prefix. Returns 0 if not prefixed
- * or the length of the prefix if it is.
- */
-extern size_t is_prefixed(const char *str, const char *pfx);
-
-/**
- * Match an integer string, returning 1 if matched, 0 if not.
- */
-extern int is_integer(int *out, const char *str, int allow_negative);
-
-struct args_info {
- int argc;
- char **argv;
- int pos;
-};
-#define ARGS_INFO_INIT { argc, argv, 0 }
-
-/**
- * Check current `args` entry against `opt` string. If it matches
- * exactly, take the next arg as a string; if it matches as a prefix with
- * an equal sign, take the remainder as a string; if value not supplied,
- * default value `def` will be given. otherwise return 0.
- */
-extern int optional_str_arg(
- const char **out, struct args_info *args, const char *opt, const char *def);
-
-/**
- * Check current `args` entry against `opt` string. If it matches
- * exactly, take the next arg as a string; if it matches as a prefix with
- * an equal sign, take the remainder as a string; otherwise return 0.
- */
-extern int match_str_arg(
- const char **out, struct args_info *args, const char *opt);
-
-/**
- * Check current `args` entry against `opt` string parsing as uint16. If
- * `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
- * is a prefix (equal sign optional), take the remainder of the arg as a
- * uint16_t value; otherwise return 0.
- */
-extern int match_uint16_arg(
- uint16_t *out, struct args_info *args, const char *opt);
-
-/**
- * Check current `args` entry against `opt` string parsing as uint32. If
- * `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
- * is a prefix (equal sign optional), take the remainder of the arg as a
- * uint32_t value; otherwise return 0.
- */
-extern int match_uint32_arg(
- uint32_t *out, struct args_info *args, const char *opt);
-
-/**
- * Check current `args` entry against `opt` string parsing as int. If
- * `opt` matches exactly, take the next arg as an int value; if it matches
- * as a prefix (equal sign optional), take the remainder of the arg as a
- * int value; otherwise return 0.
+ * Read a file into a buffer
+ *
+ * @param path The path to the file that shall be read
+ * @return NUL-terminated buffer if the file was successfully read, NULL-pointer otherwise
*/
-extern int match_int_arg(
- int *out, struct args_info *args, const char *opt, int allow_negative);
+extern char *read_file(const char *path);
/**
- * Check current `args` entry against a "bool" `opt` (ie. --[no-]progress).
- * If `opt` matches positively, out will be set to 1, or if `opt` matches
- * negatively, out will be set to 0, and in both cases 1 will be returned.
- * If neither the positive or the negative form of opt matched, out will be -1,
- * and 0 will be returned.
+ * Exit the program, printing error to stderr
*/
-extern int match_bool_arg(int *out, struct args_info *args, const char *opt);
+extern void fatal(const char *message, const char *extra);
/**
* Basic output function for plain text diff output
* Convert a refish to an annotated commit.
*/
extern int resolve_refish(git_annotated_commit **commit, git_repository *repo, const char *refish);
+
+/**
+ * Acquire credentials via command line
+ */
+extern int cred_acquire_cb(git_credential **out,
+ const char *url,
+ const char *username_from_url,
+ unsigned int allowed_types,
+ void *payload);
+
+#endif
--- /dev/null
+/*
+ * libgit2 "config" example - shows how to use the config API
+ *
+ * Written by the libgit2 contributors
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include "common.h"
+
+static int config_get(git_config *cfg, const char *key)
+{
+ git_config_entry *entry;
+ int error;
+
+ if ((error = git_config_get_entry(&entry, cfg, key)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ printf("Unable to get configuration: %s\n", git_error_last()->message);
+ return 1;
+ }
+
+ puts(entry->value);
+ return 0;
+}
+
+static int config_set(git_config *cfg, const char *key, const char *value)
+{
+ if (git_config_set_string(cfg, key, value) < 0) {
+ printf("Unable to set configuration: %s\n", git_error_last()->message);
+ return 1;
+ }
+ return 0;
+}
+
+int lg2_config(git_repository *repo, int argc, char **argv)
+{
+ git_config *cfg;
+ int error;
+
+ if ((error = git_repository_config(&cfg, repo)) < 0) {
+ printf("Unable to obtain repository config: %s\n", git_error_last()->message);
+ goto out;
+ }
+
+ if (argc == 2) {
+ error = config_get(cfg, argv[1]);
+ } else if (argc == 3) {
+ error = config_set(cfg, argv[1], argv[2]);
+ } else {
+ printf("USAGE: %s config <KEY> [<VALUE>]\n", argv[0]);
+ error = 1;
+ }
+
+out:
+ return error;
+}
*/
#include "common.h"
-#include <assert.h>
/**
* The following example partially reimplements the `git describe` command
*/
/** describe_options represents the parsed command line options */
-typedef struct {
+struct describe_options {
const char **commits;
size_t commit_count;
git_describe_options describe_options;
git_describe_format_options format_options;
-} describe_options;
+};
-typedef struct args_info args_info;
-
-static void opts_add_commit(describe_options *opts, const char *commit)
+static void opts_add_commit(struct describe_options *opts, const char *commit)
{
size_t sz;
assert(opts != NULL);
sz = ++opts->commit_count * sizeof(opts->commits[0]);
- opts->commits = xrealloc(opts->commits, sz);
+ opts->commits = xrealloc((void *) opts->commits, sz);
opts->commits[opts->commit_count - 1] = commit;
}
-static void do_describe_single(git_repository *repo, describe_options *opts, const char *rev)
+static void do_describe_single(git_repository *repo, struct describe_options *opts, const char *rev)
{
git_object *commit;
git_describe_result *describe_result;
git_buf buf = { 0 };
-
+
if (rev) {
check_lg2(git_revparse_single(&commit, repo, rev),
"Failed to lookup rev", rev);
printf("%s\n", buf.ptr);
}
-static void do_describe(git_repository *repo, describe_options *opts)
+static void do_describe(git_repository *repo, struct describe_options *opts)
{
if (opts->commit_count == 0)
do_describe_single(repo, opts, NULL);
}
/** Parse command line arguments */
-static void parse_options(describe_options *opts, int argc, char **argv)
+static void parse_options(struct describe_options *opts, int argc, char **argv)
{
- args_info args = ARGS_INFO_INIT;
+ struct args_info args = ARGS_INFO_INIT;
for (args.pos = 1; args.pos < argc; ++args.pos) {
const char *curr = argv[args.pos];
}
/** Initialize describe_options struct */
-static void describe_options_init(describe_options *opts)
+static void describe_options_init(struct describe_options *opts)
{
memset(opts, 0, sizeof(*opts));
opts->commits = NULL;
opts->commit_count = 0;
- git_describe_init_options(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION);
- git_describe_init_format_options(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
+ git_describe_options_init(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION);
+ git_describe_format_options_init(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
}
-int main(int argc, char **argv)
+int lg2_describe(git_repository *repo, int argc, char **argv)
{
- git_repository *repo;
- describe_options opts;
-
- git_libgit2_init();
-
- check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
- "Could not open repository", NULL);
+ struct describe_options opts;
describe_options_init(&opts);
parse_options(&opts, argc, argv);
do_describe(repo, &opts);
- git_repository_free(repo);
- git_libgit2_shutdown();
-
return 0;
}
CACHE_NONE = 2
};
-/** The 'opts' struct captures all the various parsed command line options. */
-struct opts {
+/** The 'diff_options' struct captures all the various parsed command line options. */
+struct diff_options {
git_diff_options diffopts;
git_diff_find_options findopts;
int color;
+ int no_index;
int cache;
int output;
git_diff_format_t format;
/** These functions are implemented at the end */
static void usage(const char *message, const char *arg);
-static void parse_opts(struct opts *o, int argc, char *argv[]);
+static void parse_opts(struct diff_options *o, int argc, char *argv[]);
static int color_printer(
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*);
-static void diff_print_stats(git_diff *diff, struct opts *o);
+static void diff_print_stats(git_diff *diff, struct diff_options *o);
+static void compute_diff_no_index(git_diff **diff, struct diff_options *o);
-int main(int argc, char *argv[])
+int lg2_diff(git_repository *repo, int argc, char *argv[])
{
- git_repository *repo = NULL;
git_tree *t1 = NULL, *t2 = NULL;
git_diff *diff;
- struct opts o = {
+ struct diff_options o = {
GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT,
- -1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "."
+ -1, -1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "."
};
- git_libgit2_init();
-
parse_opts(&o, argc, argv);
- check_lg2(git_repository_open_ext(&repo, o.dir, 0, NULL),
- "Could not open repository", o.dir);
-
/**
* Possible argument patterns:
*
* * <sha1>
* * --cached
* * --nocache (don't use index data in diff at all)
+ * * --no-index <file1> <file2>
* * nothing
*
* Currently ranged arguments like <sha1>..<sha2> and <sha1>...<sha2>
* are not supported in this example
*/
- if (o.treeish1)
- treeish_to_tree(&t1, repo, o.treeish1);
- if (o.treeish2)
- treeish_to_tree(&t2, repo, o.treeish2);
-
- if (t1 && t2)
- check_lg2(
- git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
- "diff trees", NULL);
- else if (o.cache != CACHE_NORMAL) {
- if (!t1)
- treeish_to_tree(&t1, repo, "HEAD");
+ if (o.no_index >= 0) {
+ compute_diff_no_index(&diff, &o);
+ } else {
+ if (o.treeish1)
+ treeish_to_tree(&t1, repo, o.treeish1);
+ if (o.treeish2)
+ treeish_to_tree(&t2, repo, o.treeish2);
- if (o.cache == CACHE_NONE)
+ if (t1 && t2)
+ check_lg2(
+ git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
+ "diff trees", NULL);
+ else if (o.cache != CACHE_NORMAL) {
+ if (!t1)
+ treeish_to_tree(&t1, repo, "HEAD");
+
+ if (o.cache == CACHE_NONE)
+ check_lg2(
+ git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts),
+ "diff tree to working directory", NULL);
+ else
+ check_lg2(
+ git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
+ "diff tree to index", NULL);
+ }
+ else if (t1)
check_lg2(
- git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts),
+ git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL);
else
check_lg2(
- git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
- "diff tree to index", NULL);
- }
- else if (t1)
- check_lg2(
- git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
- "diff tree to working directory", NULL);
- else
- check_lg2(
- git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
- "diff index to working directory", NULL);
+ git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
+ "diff index to working directory", NULL);
- /** Apply rename and copy detection if requested. */
+ /** Apply rename and copy detection if requested. */
- if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0)
- check_lg2(
- git_diff_find_similar(diff, &o.findopts),
- "finding renames and copies", NULL);
+ if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0)
+ check_lg2(
+ git_diff_find_similar(diff, &o.findopts),
+ "finding renames and copies", NULL);
+ }
/** Generate simple output using libgit2 display helper. */
}
/** Cleanup before exiting. */
-
git_diff_free(diff);
git_tree_free(t1);
git_tree_free(t2);
- git_repository_free(repo);
-
- git_libgit2_shutdown();
return 0;
}
+static void compute_diff_no_index(git_diff **diff, struct diff_options *o) {
+ git_patch *patch = NULL;
+ char *file1_str = NULL;
+ char *file2_str = NULL;
+ git_buf buf = {0};
+
+ if (!o->treeish1 || !o->treeish2) {
+ usage("two files should be provided as arguments", NULL);
+ }
+ file1_str = read_file(o->treeish1);
+ if (file1_str == NULL) {
+ usage("file cannot be read", o->treeish1);
+ }
+ file2_str = read_file(o->treeish2);
+ if (file2_str == NULL) {
+ usage("file cannot be read", o->treeish2);
+ }
+ check_lg2(
+ git_patch_from_buffers(&patch, file1_str, strlen(file1_str), o->treeish1, file2_str, strlen(file2_str), o->treeish2, &o->diffopts),
+ "patch buffers", NULL);
+ check_lg2(
+ git_patch_to_buf(&buf, patch),
+ "patch to buf", NULL);
+ check_lg2(
+ git_diff_from_buffer(diff, buf.ptr, buf.size),
+ "diff from patch", NULL);
+ git_patch_free(patch);
+ git_buf_dispose(&buf);
+ free(file1_str);
+ free(file2_str);
+}
+
static void usage(const char *message, const char *arg)
{
if (message && arg)
}
/** Parse arguments as copied from git-diff. */
-static void parse_opts(struct opts *o, int argc, char *argv[])
+static void parse_opts(struct diff_options *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
-
for (args.pos = 1; args.pos < argc; ++args.pos) {
const char *a = argv[args.pos];
o->output |= OUTPUT_DIFF;
o->format = GIT_DIFF_FORMAT_PATCH;
}
- else if (!strcmp(a, "--cached"))
+ else if (!strcmp(a, "--cached")) {
o->cache = CACHE_ONLY;
- else if (!strcmp(a, "--nocache"))
+ if (o->no_index >= 0) usage("--cached and --no-index are incompatible", NULL);
+ } else if (!strcmp(a, "--nocache"))
o->cache = CACHE_NONE;
else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name"))
o->format = GIT_DIFF_FORMAT_NAME_ONLY;
o->format = GIT_DIFF_FORMAT_RAW;
o->diffopts.id_abbrev = 40;
}
- else if (!strcmp(a, "--color"))
+ else if (!strcmp(a, "--no-index")) {
+ o->no_index = 0;
+ if (o->cache == CACHE_ONLY) usage("--cached and --no-index are incompatible", NULL);
+ } else if (!strcmp(a, "--color"))
o->color = 0;
else if (!strcmp(a, "--no-color"))
o->color = -1;
}
/** Display diff output with "--stat", "--numstat", or "--shortstat" */
-static void diff_print_stats(git_diff *diff, struct opts *o)
+static void diff_print_stats(git_diff *diff, struct diff_options *o)
{
git_diff_stats *stats;
git_buf b = GIT_BUF_INIT_CONST(NULL, 0);
--- /dev/null
+#include "common.h"
+
+static int progress_cb(const char *str, int len, void *data)
+{
+ (void)data;
+ printf("remote: %.*s", len, str);
+ fflush(stdout); /* We don't have the \n to force the flush */
+ return 0;
+}
+
+/**
+ * This function gets called for each remote-tracking branch that gets
+ * updated. The message we output depends on whether it's a new one or
+ * an update.
+ */
+static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
+{
+ char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
+ (void)data;
+
+ git_oid_fmt(b_str, b);
+ b_str[GIT_OID_HEXSZ] = '\0';
+
+ if (git_oid_is_zero(a)) {
+ printf("[new] %.20s %s\n", b_str, refname);
+ } else {
+ git_oid_fmt(a_str, a);
+ a_str[GIT_OID_HEXSZ] = '\0';
+ printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname);
+ }
+
+ return 0;
+}
+
+/**
+ * This gets called during the download and indexing. Here we show
+ * processed and total objects in the pack and the amount of received
+ * data. Most frontends will probably want to show a percentage and
+ * the download rate.
+ */
+static int transfer_progress_cb(const git_indexer_progress *stats, void *payload)
+{
+ (void)payload;
+
+ if (stats->received_objects == stats->total_objects) {
+ printf("Resolving deltas %u/%u\r",
+ stats->indexed_deltas, stats->total_deltas);
+ } else if (stats->total_objects > 0) {
+ printf("Received %u/%u objects (%u) in %" PRIuZ " bytes\r",
+ stats->received_objects, stats->total_objects,
+ stats->indexed_objects, stats->received_bytes);
+ }
+ return 0;
+}
+
+/** Entry point for this command */
+int lg2_fetch(git_repository *repo, int argc, char **argv)
+{
+ git_remote *remote = NULL;
+ const git_indexer_progress *stats;
+ git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s fetch <repo>\n", argv[-1]);
+ return EXIT_FAILURE;
+ }
+
+ /* Figure out whether it's a named remote or a URL */
+ printf("Fetching %s for repo %p\n", argv[1], repo);
+ if (git_remote_lookup(&remote, repo, argv[1]) < 0)
+ if (git_remote_create_anonymous(&remote, repo, argv[1]) < 0)
+ goto on_error;
+
+ /* Set up the callbacks (only update_tips for now) */
+ fetch_opts.callbacks.update_tips = &update_cb;
+ fetch_opts.callbacks.sideband_progress = &progress_cb;
+ fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
+ fetch_opts.callbacks.credentials = cred_acquire_cb;
+
+ /**
+ * Perform the fetch with the configured refspecs from the
+ * config. Update the reflog for the updated references with
+ * "fetch".
+ */
+ if (git_remote_fetch(remote, NULL, &fetch_opts, "fetch") < 0)
+ goto on_error;
+
+ /**
+ * If there are local objects (we got a thin pack), then tell
+ * the user how many objects we saved from having to cross the
+ * network.
+ */
+ stats = git_remote_stats(remote);
+ if (stats->local_objects > 0) {
+ printf("\rReceived %u/%u objects in %" PRIuZ " bytes (used %u local objects)\n",
+ stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects);
+ } else{
+ printf("\rReceived %u/%u objects in %" PRIuZ "bytes\n",
+ stats->indexed_objects, stats->total_objects, stats->received_bytes);
+ }
+
+ git_remote_free(remote);
+
+ return 0;
+
+ on_error:
+ git_remote_free(remote);
+ return -1;
+}
#include <git2.h>
-#include <stdio.h>
#include "common.h"
static int show_ref(git_reference *ref, void *data)
{
- git_repository *repo = data;
- git_reference *resolved = NULL;
- char hex[GIT_OID_HEXSZ+1];
- const git_oid *oid;
- git_object *obj;
-
- if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC)
- check_lg2(git_reference_resolve(&resolved, ref),
- "Unable to resolve symbolic reference",
- git_reference_name(ref));
-
- oid = git_reference_target(resolved ? resolved : ref);
- git_oid_fmt(hex, oid);
- hex[GIT_OID_HEXSZ] = 0;
- check_lg2(git_object_lookup(&obj, repo, oid, GIT_OBJECT_ANY),
- "Unable to lookup object", hex);
-
- printf("%s %-6s\t%s\n",
- hex,
- git_object_type2string(git_object_type(obj)),
- git_reference_name(ref));
-
- if (resolved)
- git_reference_free(resolved);
- return 0;
+ git_repository *repo = data;
+ git_reference *resolved = NULL;
+ char hex[GIT_OID_HEXSZ+1];
+ const git_oid *oid;
+ git_object *obj;
+
+ if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC)
+ check_lg2(git_reference_resolve(&resolved, ref),
+ "Unable to resolve symbolic reference",
+ git_reference_name(ref));
+
+ oid = git_reference_target(resolved ? resolved : ref);
+ git_oid_fmt(hex, oid);
+ hex[GIT_OID_HEXSZ] = 0;
+ check_lg2(git_object_lookup(&obj, repo, oid, GIT_OBJECT_ANY),
+ "Unable to lookup object", hex);
+
+ printf("%s %-6s\t%s\n",
+ hex,
+ git_object_type2string(git_object_type(obj)),
+ git_reference_name(ref));
+
+ if (resolved)
+ git_reference_free(resolved);
+ return 0;
}
-int main(int argc, char **argv)
+int lg2_for_each_ref(git_repository *repo, int argc, char **argv)
{
- git_repository *repo;
- git_libgit2_init();
-
- if (argc != 1 || argv[1] /* silence -Wunused-parameter */)
- fatal("Sorry, no for-each-ref options supported yet", NULL);
-
- check_lg2(git_repository_open(&repo, "."),
- "Could not open repository", NULL);
- check_lg2(git_reference_foreach(repo, show_ref, repo),
- "Could not iterate over references", NULL);
-
- git_libgit2_shutdown();
- return 0;
+ UNUSED(argv);
+
+ if (argc != 1)
+ fatal("Sorry, no for-each-ref options supported yet", NULL);
+
+ check_lg2(git_reference_foreach(repo, show_ref, repo),
+ "Could not iterate over references", NULL);
+
+ return 0;
}
* [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
*/
+#include "common.h"
+
/**
* ### Includes
*
* that you need. It should be the only thing you need to include in order
* to compile properly and get all the libgit2 API.
*/
-#include <git2.h>
-#include <stdio.h>
-#include <string.h>
+#include "git2.h"
static void oid_parsing(git_oid *out);
static void object_database(git_repository *repo, git_oid *oid);
exit(1);
}
-int main (int argc, char** argv)
+int lg2_general(git_repository *repo, int argc, char** argv)
{
int error;
git_oid oid;
char *repo_path;
- git_repository *repo;
/**
* Initialize the library, this will set up any global state which libgit2 needs
static void index_walking(git_repository *repo)
{
git_index *index;
- unsigned int i, ecount;
+ size_t i, ecount;
printf("\n*Index Walking*\n");
git_reference_free(ref);
}
- git_strarray_free(&ref_list);
+ git_strarray_dispose(&ref_list);
}
/**
--- /dev/null
+#include "common.h"
+
+/*
+ * This could be run in the main loop whilst the application waits for
+ * the indexing to finish in a worker thread
+ */
+static int index_cb(const git_indexer_progress *stats, void *data)
+{
+ (void)data;
+ printf("\rProcessing %u of %u", stats->indexed_objects, stats->total_objects);
+
+ return 0;
+}
+
+int lg2_index_pack(git_repository *repo, int argc, char **argv)
+{
+ git_indexer *idx;
+ git_indexer_progress stats = {0, 0};
+ int error;
+ char hash[GIT_OID_HEXSZ + 1] = {0};
+ int fd;
+ ssize_t read_bytes;
+ char buf[512];
+
+ (void)repo;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s index-pack <packfile>\n", argv[-1]);
+ return EXIT_FAILURE;
+ }
+
+ if (git_indexer_new(&idx, ".", 0, NULL, NULL) < 0) {
+ puts("bad idx");
+ return -1;
+ }
+
+ if ((fd = open(argv[1], 0)) < 0) {
+ perror("open");
+ return -1;
+ }
+
+ do {
+ read_bytes = read(fd, buf, sizeof(buf));
+ if (read_bytes < 0)
+ break;
+
+ if ((error = git_indexer_append(idx, buf, read_bytes, &stats)) < 0)
+ goto cleanup;
+
+ index_cb(&stats, NULL);
+ } while (read_bytes > 0);
+
+ if (read_bytes < 0) {
+ error = -1;
+ perror("failed reading");
+ goto cleanup;
+ }
+
+ if ((error = git_indexer_commit(idx, &stats)) < 0)
+ goto cleanup;
+
+ printf("\rIndexing %u of %u\n", stats.indexed_objects, stats.total_objects);
+
+ git_oid_fmt(hash, git_indexer_hash(idx));
+ puts(hash);
+
+ cleanup:
+ close(fd);
+ git_indexer_free(idx);
+ return error;
+}
*/
/** Forward declarations of helpers */
-struct opts {
+struct init_opts {
int no_options;
int quiet;
int bare;
const char *dir;
};
static void create_initial_commit(git_repository *repo);
-static void parse_opts(struct opts *o, int argc, char *argv[]);
+static void parse_opts(struct init_opts *o, int argc, char *argv[]);
-
-int main(int argc, char *argv[])
+int lg2_init(git_repository *repo, int argc, char *argv[])
{
- git_repository *repo = NULL;
- struct opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
-
- git_libgit2_init();
+ struct init_opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
parse_opts(&o, argc, argv);
}
git_repository_free(repo);
- git_libgit2_shutdown();
return 0;
}
return 0;
}
-static void parse_opts(struct opts *o, int argc, char *argv[])
+static void parse_opts(struct init_opts *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
const char *sharedarg;
}
if (!o->dir)
- usage("must specify directory to init", NULL);
+ usage("must specify directory to init", "");
}
--- /dev/null
+#include "common.h"
+
+/* This part is not strictly libgit2-dependent, but you can use this
+ * as a starting point for a git-like tool */
+
+typedef int (*git_command_fn)(git_repository *, int , char **);
+
+struct {
+ char *name;
+ git_command_fn fn;
+ char requires_repo;
+} commands[] = {
+ { "add", lg2_add, 1 },
+ { "blame", lg2_blame, 1 },
+ { "cat-file", lg2_cat_file, 1 },
+ { "checkout", lg2_checkout, 1 },
+ { "clone", lg2_clone, 0 },
+ { "commit", lg2_commit, 1 },
+ { "config", lg2_config, 1 },
+ { "describe", lg2_describe, 1 },
+ { "diff", lg2_diff, 1 },
+ { "fetch", lg2_fetch, 1 },
+ { "for-each-ref", lg2_for_each_ref, 1 },
+ { "general", lg2_general, 0 },
+ { "index-pack", lg2_index_pack, 1 },
+ { "init", lg2_init, 0 },
+ { "log", lg2_log, 1 },
+ { "ls-files", lg2_ls_files, 1 },
+ { "ls-remote", lg2_ls_remote, 1 },
+ { "merge", lg2_merge, 1 },
+ { "push", lg2_push, 1 },
+ { "remote", lg2_remote, 1 },
+ { "rev-list", lg2_rev_list, 1 },
+ { "rev-parse", lg2_rev_parse, 1 },
+ { "show-index", lg2_show_index, 0 },
+ { "stash", lg2_stash, 1 },
+ { "status", lg2_status, 1 },
+ { "tag", lg2_tag, 1 },
+};
+
+static int run_command(git_command_fn fn, git_repository *repo, struct args_info args)
+{
+ int error;
+
+ /* Run the command. If something goes wrong, print the error message to stderr */
+ error = fn(repo, args.argc - args.pos, &args.argv[args.pos]);
+ if (error < 0) {
+ if (git_error_last() == NULL)
+ fprintf(stderr, "Error without message");
+ else
+ fprintf(stderr, "Bad news:\n %s\n", git_error_last()->message);
+ }
+
+ return !!error;
+}
+
+static int usage(const char *prog)
+{
+ size_t i;
+
+ fprintf(stderr, "usage: %s <cmd>...\n\nAvailable commands:\n\n", prog);
+ for (i = 0; i < ARRAY_SIZE(commands); i++)
+ fprintf(stderr, "\t%s\n", commands[i].name);
+
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ struct args_info args = ARGS_INFO_INIT;
+ git_repository *repo = NULL;
+ const char *git_dir = NULL;
+ int return_code = 1;
+ size_t i;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ git_libgit2_init();
+
+ for (args.pos = 1; args.pos < args.argc; ++args.pos) {
+ char *a = args.argv[args.pos];
+
+ if (a[0] != '-') {
+ /* non-arg */
+ break;
+ } else if (optional_str_arg(&git_dir, &args, "--git-dir", ".git")) {
+ continue;
+ } else if (match_arg_separator(&args)) {
+ break;
+ }
+ }
+
+ if (args.pos == args.argc)
+ usage(argv[0]);
+
+ if (!git_dir)
+ git_dir = ".";
+
+ for (i = 0; i < ARRAY_SIZE(commands); ++i) {
+ if (strcmp(args.argv[args.pos], commands[i].name))
+ continue;
+
+ /*
+ * Before running the actual command, create an instance
+ * of the local repository and pass it to the function.
+ * */
+ if (commands[i].requires_repo) {
+ check_lg2(git_repository_open_ext(&repo, git_dir, 0, NULL),
+ "Unable to open repository '%s'", git_dir);
+ }
+
+ return_code = run_command(commands[i].fn, repo, args);
+ goto shutdown;
+ }
+
+ fprintf(stderr, "Command not found: %s\n", argv[1]);
+
+shutdown:
+ git_repository_free(repo);
+ git_libgit2_shutdown();
+
+ return return_code;
+}
static int signature_matches(const git_signature *sig, const char *filter);
static int log_message_matches(const git_commit *commit, const char *filter);
-int main(int argc, char *argv[])
+int lg2_log(git_repository *repo, int argc, char *argv[])
{
int i, count = 0, printed = 0, parents, last_arg;
struct log_state s;
git_commit *commit = NULL;
git_pathspec *ps = NULL;
- git_libgit2_init();
-
/** Parse arguments and set up revwalker. */
-
last_arg = parse_options(&s, &opt, argc, argv);
+ s.repo = repo;
diffopts.pathspec.strings = &argv[last_arg];
diffopts.pathspec.count = argc - last_arg;
git_pathspec_free(ps);
git_revwalk_free(s.walker);
- git_repository_free(s.repo);
- git_libgit2_shutdown();
return 0;
}
git_revspec revs;
int hide = 0;
- /** Open repo on demand if it isn't already open. */
- if (!s->repo) {
- if (!s->repodir) s->repodir = ".";
- check_lg2(git_repository_open_ext(&s->repo, s->repodir, 0, NULL),
- "Could not open repository", s->repodir);
- }
-
if (!revstr) {
push_rev(s, NULL, hide);
return 0;
else
/** Try failed revision parse as filename. */
break;
- } else if (!strcmp(a, "--")) {
- ++args.pos;
+ } else if (!match_arg_separator(&args)) {
break;
}
else if (!strcmp(a, "--date-order"))
else if (!strcmp(a, "--reverse"))
set_sorting(s, GIT_SORT_REVERSE);
else if (match_str_arg(&opt->author, &args, "--author"))
- /** Found valid --author */;
+ /** Found valid --author */
+ ;
else if (match_str_arg(&opt->committer, &args, "--committer"))
- /** Found valid --committer */;
+ /** Found valid --committer */
+ ;
else if (match_str_arg(&opt->grep, &args, "--grep"))
- /** Found valid --grep */;
+ /** Found valid --grep */
+ ;
else if (match_str_arg(&s->repodir, &args, "--git-dir"))
- /** Found git-dir. */;
+ /** Found git-dir. */
+ ;
else if (match_int_arg(&opt->skip, &args, "--skip", 0))
- /** Found valid --skip. */;
+ /** Found valid --skip. */
+ ;
else if (match_int_arg(&opt->limit, &args, "--max-count", 0))
- /** Found valid --max-count. */;
+ /** Found valid --max-count. */
+ ;
else if (a[1] >= '0' && a[1] <= '9')
is_integer(&opt->limit, a + 1, 0);
else if (match_int_arg(&opt->limit, &args, "-n", 0))
- /** Found valid -n. */;
+ /** Found valid -n. */
+ ;
else if (!strcmp(a, "--merges"))
opt->min_parents = 2;
else if (!strcmp(a, "--no-merges"))
else if (!strcmp(a, "--no-max-parents"))
opt->max_parents = -1;
else if (match_int_arg(&opt->max_parents, &args, "--max-parents=", 1))
- /** Found valid --max-parents. */;
+ /** Found valid --max-parents. */
+ ;
else if (match_int_arg(&opt->min_parents, &args, "--min-parents=", 0))
- /** Found valid --min_parents. */;
+ /** Found valid --min_parents. */
+ ;
else if (!strcmp(a, "-p") || !strcmp(a, "-u") || !strcmp(a, "--patch"))
opt->show_diff = 1;
else if (!strcmp(a, "--log-size"))
*/
#include "common.h"
-#include "array.h"
/**
* This example demonstrates the libgit2 index APIs to roughly
* This currently supports the default behavior and the `--error-unmatch` option.
*/
-typedef struct {
+struct ls_options {
int error_unmatch;
char *files[1024];
size_t file_count;
-} ls_options;
+};
static void usage(const char *message, const char *arg)
{
exit(1);
}
-static int parse_options(ls_options *opts, int argc, char *argv[])
+static int parse_options(struct ls_options *opts, int argc, char *argv[])
{
int parsing_files = 0;
int i;
- memset(opts, 0, sizeof(ls_options));
+ memset(opts, 0, sizeof(struct ls_options));
if (argc < 2)
return 0;
return 0;
}
-static int print_paths(ls_options *opts, git_index *index)
+static int print_paths(struct ls_options *opts, git_index *index)
{
size_t i;
const git_index_entry *entry;
return 0;
}
-int main(int argc, char *argv[])
+int lg2_ls_files(git_repository *repo, int argc, char *argv[])
{
- ls_options opts;
- git_repository *repo = NULL;
git_index *index = NULL;
+ struct ls_options opts;
int error;
if ((error = parse_options(&opts, argc, argv)) < 0)
return error;
- git_libgit2_init();
-
- if ((error = git_repository_open_ext(&repo, ".", 0, NULL)) < 0)
- goto cleanup;
-
if ((error = git_repository_index(&index, repo)) < 0)
goto cleanup;
cleanup:
git_index_free(index);
- git_repository_free(repo);
- git_libgit2_shutdown();
return error;
}
--- /dev/null
+#include "common.h"
+
+static int use_remote(git_repository *repo, char *name)
+{
+ git_remote *remote = NULL;
+ int error;
+ const git_remote_head **refs;
+ size_t refs_len, i;
+ git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
+
+ /* Find the remote by name */
+ error = git_remote_lookup(&remote, repo, name);
+ if (error < 0) {
+ error = git_remote_create_anonymous(&remote, repo, name);
+ if (error < 0)
+ goto cleanup;
+ }
+
+ /**
+ * Connect to the remote and call the printing function for
+ * each of the remote references.
+ */
+ callbacks.credentials = cred_acquire_cb;
+
+ error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, NULL);
+ if (error < 0)
+ goto cleanup;
+
+ /**
+ * Get the list of references on the remote and print out
+ * their name next to what they point to.
+ */
+ if (git_remote_ls(&refs, &refs_len, remote) < 0)
+ goto cleanup;
+
+ for (i = 0; i < refs_len; i++) {
+ char oid[GIT_OID_HEXSZ + 1] = {0};
+ git_oid_fmt(oid, &refs[i]->oid);
+ printf("%s\t%s\n", oid, refs[i]->name);
+ }
+
+cleanup:
+ git_remote_free(remote);
+ return error;
+}
+
+/** Entry point for this command */
+int lg2_ls_remote(git_repository *repo, int argc, char **argv)
+{
+ int error;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s ls-remote <remote>\n", argv[-1]);
+ return EXIT_FAILURE;
+ }
+
+ error = use_remote(repo, argv[1]);
+
+ return error;
+}
*/
#include "common.h"
-#include <assert.h>
-
-#ifdef _MSC_VER
-#define snprintf sprintf_s
-#endif
/** The following example demonstrates how to do merges with libgit2.
*
*
*/
-typedef struct {
+struct merge_options {
const char **heads;
size_t heads_count;
size_t annotated_count;
int no_commit : 1;
-} merge_options;
+};
static void print_usage(void)
{
exit(1);
}
-static void merge_options_init(merge_options *opts)
+static void merge_options_init(struct merge_options *opts)
{
memset(opts, 0, sizeof(*opts));
opts->annotated_count = 0;
}
-static void opts_add_refish(merge_options *opts, const char *refish)
+static void opts_add_refish(struct merge_options *opts, const char *refish)
{
size_t sz;
assert(opts != NULL);
sz = ++opts->heads_count * sizeof(opts->heads[0]);
- opts->heads = xrealloc(opts->heads, sz);
+ opts->heads = xrealloc((void *) opts->heads, sz);
opts->heads[opts->heads_count - 1] = refish;
}
-static void parse_options(const char **repo_path, merge_options *opts, int argc, char **argv)
+static void parse_options(const char **repo_path, struct merge_options *opts, int argc, char **argv)
{
struct args_info args = ARGS_INFO_INIT;
}
}
-static int resolve_heads(git_repository *repo, merge_options *opts)
+static int resolve_heads(git_repository *repo, struct merge_options *opts)
{
git_annotated_commit **annotated = calloc(opts->heads_count, sizeof(git_annotated_commit *));
size_t annotated_count = 0, i;
git_index_conflict_iterator_free(conflicts);
}
-static int create_merge_commit(git_repository *repo, git_index *index, merge_options *opts)
+static int create_merge_commit(git_repository *repo, git_index *index, struct merge_options *opts)
{
git_oid tree_oid, commit_oid;
git_tree *tree;
check_lg2(git_repository_head(&head_ref, repo), "failed to get repo HEAD", NULL);
if (resolve_refish(&merge_commit, repo, opts->heads[0])) {
fprintf(stderr, "failed to resolve refish %s", opts->heads[0]);
+ free(parents);
return -1;
}
return err;
}
-int main(int argc, char **argv)
+int lg2_merge(git_repository *repo, int argc, char **argv)
{
- git_repository *repo = NULL;
- merge_options opts;
+ struct merge_options opts;
git_index *index;
git_repository_state_t state;
git_merge_analysis_t analysis;
merge_options_init(&opts);
parse_options(&path, &opts, argc, argv);
- git_libgit2_init();
-
- check_lg2(git_repository_open_ext(&repo, path, 0, NULL),
- "Could not open repository", NULL);
-
state = git_repository_state(repo);
if (state != GIT_REPOSITORY_STATE_NONE) {
fprintf(stderr, "repository is in unexpected state %d\n", state);
}
cleanup:
- free(opts.heads);
+ free((char **)opts.heads);
free(opts.annotated);
- git_repository_free(repo);
- git_libgit2_shutdown();
return 0;
}
+++ /dev/null
-default: all
-
-CC = gcc
-CFLAGS += -g
-CFLAGS += -I../../include
-LDFLAGS += -L../../build -L../..
-LIBRARIES += -lgit2 -lpthread
-
-OBJECTS = \
- git2.o \
- ls-remote.o \
- fetch.o \
- clone.o \
- index-pack.o \
- common.o
-
-all: $(OBJECTS)
- $(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS) $(LIBRARIES)
-
-clean:
- $(RM) $(OBJECTS)
- $(RM) git2
+++ /dev/null
-#include "common.h"
-#include <git2.h>
-#include <git2/clone.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-# include <pthread.h>
-# include <unistd.h>
-#endif
-
-typedef struct progress_data {
- git_transfer_progress fetch_progress;
- size_t completed_steps;
- size_t total_steps;
- const char *path;
-} progress_data;
-
-static void print_progress(const progress_data *pd)
-{
- int network_percent = pd->fetch_progress.total_objects > 0 ?
- (100*pd->fetch_progress.received_objects) / pd->fetch_progress.total_objects :
- 0;
- int index_percent = pd->fetch_progress.total_objects > 0 ?
- (100*pd->fetch_progress.indexed_objects) / pd->fetch_progress.total_objects :
- 0;
-
- int checkout_percent = pd->total_steps > 0
- ? (100 * pd->completed_steps) / pd->total_steps
- : 0;
- int kbytes = pd->fetch_progress.received_bytes / 1024;
-
- if (pd->fetch_progress.total_objects &&
- pd->fetch_progress.received_objects == pd->fetch_progress.total_objects) {
- printf("Resolving deltas %d/%d\r",
- pd->fetch_progress.indexed_deltas,
- pd->fetch_progress.total_deltas);
- } else {
- printf("net %3d%% (%4d kb, %5d/%5d) / idx %3d%% (%5d/%5d) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ ") %s\n",
- network_percent, kbytes,
- pd->fetch_progress.received_objects, pd->fetch_progress.total_objects,
- index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects,
- checkout_percent,
- pd->completed_steps, pd->total_steps,
- pd->path);
- }
-}
-
-static int sideband_progress(const char *str, int len, void *payload)
-{
- (void)payload; /* unused */
-
- printf("remote: %.*s", len, str);
- fflush(stdout);
- return 0;
-}
-
-static int fetch_progress(const git_transfer_progress *stats, void *payload)
-{
- progress_data *pd = (progress_data*)payload;
- pd->fetch_progress = *stats;
- print_progress(pd);
- return 0;
-}
-static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload)
-{
- progress_data *pd = (progress_data*)payload;
- pd->completed_steps = cur;
- pd->total_steps = tot;
- pd->path = path;
- print_progress(pd);
-}
-
-
-int do_clone(git_repository *repo, int argc, char **argv)
-{
- progress_data pd = {{0}};
- git_repository *cloned_repo = NULL;
- git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
- git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
- const char *url = argv[1];
- const char *path = argv[2];
- int error;
-
- (void)repo; /* unused */
-
- /* Validate args */
- if (argc < 3) {
- printf ("USAGE: %s <url> <path>\n", argv[0]);
- return -1;
- }
-
- /* Set up options */
- checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
- checkout_opts.progress_cb = checkout_progress;
- checkout_opts.progress_payload = &pd;
- clone_opts.checkout_opts = checkout_opts;
- clone_opts.fetch_opts.callbacks.sideband_progress = sideband_progress;
- clone_opts.fetch_opts.callbacks.transfer_progress = &fetch_progress;
- clone_opts.fetch_opts.callbacks.credentials = cred_acquire_cb;
- clone_opts.fetch_opts.callbacks.payload = &pd;
-
- /* Do the clone */
- error = git_clone(&cloned_repo, url, path, &clone_opts);
- printf("\n");
- if (error != 0) {
- const git_error *err = git_error_last();
- if (err) printf("ERROR %d: %s\n", err->klass, err->message);
- else printf("ERROR %d: no detailed info\n", error);
- }
- else if (cloned_repo) git_repository_free(cloned_repo);
- return error;
-}
+++ /dev/null
-#include "common.h"
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-/* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/
- * with permission of the original author, Martin Pool.
- * http://sourcefrog.net/weblog/software/languages/C/unused.html
- */
-#ifdef UNUSED
-#elif defined(__GNUC__)
-# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
-#elif defined(__LCLINT__)
-# define UNUSED(x) /*@unused@*/ x
-#else
-# define UNUSED(x) x
-#endif
-
-static int readline(char **out)
-{
- int c, error = 0, length = 0, allocated = 0;
- char *line = NULL;
-
- errno = 0;
-
- while ((c = getchar()) != EOF) {
- if (length == allocated) {
- allocated += 16;
-
- if ((line = realloc(line, allocated)) == NULL) {
- error = -1;
- goto error;
- }
- }
-
- if (c == '\n')
- break;
-
- line[length++] = c;
- }
-
- if (errno != 0) {
- error = -1;
- goto error;
- }
-
- line[length] = '\0';
- *out = line;
- line = NULL;
- error = length;
-error:
- free(line);
- return error;
-}
-
-int cred_acquire_cb(git_cred **out,
- const char * UNUSED(url),
- const char * UNUSED(username_from_url),
- unsigned int UNUSED(allowed_types),
- void * UNUSED(payload))
-{
- char *username = NULL, *password = NULL;
- int error;
-
- printf("Username: ");
- if (readline(&username) < 0) {
- fprintf(stderr, "Unable to read username: %s", strerror(errno));
- return -1;
- }
-
- /* Yup. Right there on your terminal. Careful where you copy/paste output. */
- printf("Password: ");
- if (readline(&password) < 0) {
- fprintf(stderr, "Unable to read password: %s", strerror(errno));
- free(username);
- return -1;
- }
-
- error = git_cred_userpass_plaintext_new(out, username, password);
-
- free(username);
- free(password);
-
- return error;
-}
+++ /dev/null
-#ifndef __COMMON_H__
-#define __COMMON_H__
-
-#include <git2.h>
-
-typedef int (*git_cb)(git_repository *, int , char **);
-
-int ls_remote(git_repository *repo, int argc, char **argv);
-int parse_pkt_line(git_repository *repo, int argc, char **argv);
-int show_remote(git_repository *repo, int argc, char **argv);
-int fetch(git_repository *repo, int argc, char **argv);
-int index_pack(git_repository *repo, int argc, char **argv);
-int do_clone(git_repository *repo, int argc, char **argv);
-
-int cred_acquire_cb(git_cred **out,
- const char * url,
- const char * username_from_url,
- unsigned int allowed_types,
- void *payload);
-
-#ifndef PRIuZ
-/* Define the printf format specifer to use for size_t output */
-#if defined(_MSC_VER) || defined(__MINGW32__)
-# define PRIuZ "Iu"
-#else
-# define PRIuZ "zu"
-#endif
-#endif
-
-#endif /* __COMMON_H__ */
+++ /dev/null
-#include "common.h"
-#include <git2.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-# include <pthread.h>
-# include <unistd.h>
-#endif
-
-static int progress_cb(const char *str, int len, void *data)
-{
- (void)data;
- printf("remote: %.*s", len, str);
- fflush(stdout); /* We don't have the \n to force the flush */
- return 0;
-}
-
-/**
- * This function gets called for each remote-tracking branch that gets
- * updated. The message we output depends on whether it's a new one or
- * an update.
- */
-static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
-{
- char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
- (void)data;
-
- git_oid_fmt(b_str, b);
- b_str[GIT_OID_HEXSZ] = '\0';
-
- if (git_oid_iszero(a)) {
- printf("[new] %.20s %s\n", b_str, refname);
- } else {
- git_oid_fmt(a_str, a);
- a_str[GIT_OID_HEXSZ] = '\0';
- printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname);
- }
-
- return 0;
-}
-
-/**
- * This gets called during the download and indexing. Here we show
- * processed and total objects in the pack and the amount of received
- * data. Most frontends will probably want to show a percentage and
- * the download rate.
- */
-static int transfer_progress_cb(const git_transfer_progress *stats, void *payload)
-{
- (void)payload;
-
- if (stats->received_objects == stats->total_objects) {
- printf("Resolving deltas %d/%d\r",
- stats->indexed_deltas, stats->total_deltas);
- } else if (stats->total_objects > 0) {
- printf("Received %d/%d objects (%d) in %" PRIuZ " bytes\r",
- stats->received_objects, stats->total_objects,
- stats->indexed_objects, stats->received_bytes);
- }
- return 0;
-}
-
-/** Entry point for this command */
-int fetch(git_repository *repo, int argc, char **argv)
-{
- git_remote *remote = NULL;
- const git_transfer_progress *stats;
- git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
-
- if (argc < 2) {
- fprintf(stderr, "usage: %s fetch <repo>\n", argv[-1]);
- return EXIT_FAILURE;
- }
-
- /* Figure out whether it's a named remote or a URL */
- printf("Fetching %s for repo %p\n", argv[1], repo);
- if (git_remote_lookup(&remote, repo, argv[1]) < 0)
- if (git_remote_create_anonymous(&remote, repo, argv[1]) < 0)
- goto on_error;
-
- /* Set up the callbacks (only update_tips for now) */
- fetch_opts.callbacks.update_tips = &update_cb;
- fetch_opts.callbacks.sideband_progress = &progress_cb;
- fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
- fetch_opts.callbacks.credentials = cred_acquire_cb;
-
- /**
- * Perform the fetch with the configured refspecs from the
- * config. Update the reflog for the updated references with
- * "fetch".
- */
- if (git_remote_fetch(remote, NULL, &fetch_opts, "fetch") < 0)
- goto on_error;
-
- /**
- * If there are local objects (we got a thin pack), then tell
- * the user how many objects we saved from having to cross the
- * network.
- */
- stats = git_remote_stats(remote);
- if (stats->local_objects > 0) {
- printf("\rReceived %d/%d objects in %" PRIuZ " bytes (used %d local objects)\n",
- stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects);
- } else{
- printf("\rReceived %d/%d objects in %" PRIuZ "bytes\n",
- stats->indexed_objects, stats->total_objects, stats->received_bytes);
- }
-
- git_remote_free(remote);
-
- return 0;
-
- on_error:
- git_remote_free(remote);
- return -1;
-}
+++ /dev/null
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "../common.h"
-#include "common.h"
-
-/* This part is not strictly libgit2-dependent, but you can use this
- * as a starting point for a git-like tool */
-
-struct {
- char *name;
- git_cb fn;
-} commands[] = {
- {"ls-remote", ls_remote},
- {"fetch", fetch},
- {"clone", do_clone},
- {"index-pack", index_pack},
- { NULL, NULL}
-};
-
-static int run_command(git_cb fn, git_repository *repo, struct args_info args)
-{
- int error;
-
- /* Run the command. If something goes wrong, print the error message to stderr */
- error = fn(repo, args.argc - args.pos, &args.argv[args.pos]);
- if (error < 0) {
- if (git_error_last() == NULL)
- fprintf(stderr, "Error without message");
- else
- fprintf(stderr, "Bad news:\n %s\n", git_error_last()->message);
- }
-
- return !!error;
-}
-
-int main(int argc, char **argv)
-{
- int i;
- int return_code = 1;
- int error;
- git_repository *repo;
- struct args_info args = ARGS_INFO_INIT;
- const char *git_dir = NULL;
-
- if (argc < 2) {
- fprintf(stderr, "usage: %s <cmd> [repo]\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- git_libgit2_init();
-
- for (args.pos = 1; args.pos < args.argc; ++args.pos) {
- char *a = args.argv[args.pos];
-
- if (a[0] != '-') {
- /* non-arg */
- break;
- } else if (optional_str_arg(&git_dir, &args, "--git-dir", ".git")) {
- continue;
- } else if (!strcmp(a, "--")) {
- /* arg separator */
- break;
- }
- }
-
- /* Before running the actual command, create an instance of the local
- * repository and pass it to the function. */
-
- error = git_repository_open(&repo, git_dir);
- if (error < 0)
- repo = NULL;
-
- for (i = 0; commands[i].name != NULL; ++i) {
- if (!strcmp(args.argv[args.pos], commands[i].name)) {
- return_code = run_command(commands[i].fn, repo, args);
- goto shutdown;
- }
- }
-
- fprintf(stderr, "Command not found: %s\n", argv[1]);
-
-shutdown:
- git_repository_free(repo);
-
- git_libgit2_shutdown();
-
- return return_code;
-}
+++ /dev/null
-#include <git2.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#ifdef _WIN32
-# include <io.h>
-# include <Windows.h>
-
-# define open _open
-# define read _read
-# define close _close
-
-#define ssize_t unsigned int
-#else
-# include <unistd.h>
-#endif
-#include "common.h"
-
-/*
- * This could be run in the main loop whilst the application waits for
- * the indexing to finish in a worker thread
- */
-static int index_cb(const git_transfer_progress *stats, void *data)
-{
- (void)data;
- printf("\rProcessing %d of %d", stats->indexed_objects, stats->total_objects);
-
- return 0;
-}
-
-int index_pack(git_repository *repo, int argc, char **argv)
-{
- git_indexer *idx;
- git_transfer_progress stats = {0, 0};
- int error;
- char hash[GIT_OID_HEXSZ + 1] = {0};
- int fd;
- ssize_t read_bytes;
- char buf[512];
-
- (void)repo;
-
- if (argc < 2) {
- fprintf(stderr, "usage: %s index-pack <packfile>\n", argv[-1]);
- return EXIT_FAILURE;
- }
-
- if (git_indexer_new(&idx, ".", 0, NULL, NULL) < 0) {
- puts("bad idx");
- return -1;
- }
-
- if ((fd = open(argv[1], 0)) < 0) {
- perror("open");
- return -1;
- }
-
- do {
- read_bytes = read(fd, buf, sizeof(buf));
- if (read_bytes < 0)
- break;
-
- if ((error = git_indexer_append(idx, buf, read_bytes, &stats)) < 0)
- goto cleanup;
-
- index_cb(&stats, NULL);
- } while (read_bytes > 0);
-
- if (read_bytes < 0) {
- error = -1;
- perror("failed reading");
- goto cleanup;
- }
-
- if ((error = git_indexer_commit(idx, &stats)) < 0)
- goto cleanup;
-
- printf("\rIndexing %d of %d\n", stats.indexed_objects, stats.total_objects);
-
- git_oid_fmt(hash, git_indexer_hash(idx));
- puts(hash);
-
- cleanup:
- close(fd);
- git_indexer_free(idx);
- return error;
-}
+++ /dev/null
-#include <git2.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "common.h"
-
-static int use_remote(git_repository *repo, char *name)
-{
- git_remote *remote = NULL;
- int error;
- const git_remote_head **refs;
- size_t refs_len, i;
- git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
-
- /* Find the remote by name */
- error = git_remote_lookup(&remote, repo, name);
- if (error < 0) {
- error = git_remote_create_anonymous(&remote, repo, name);
- if (error < 0)
- goto cleanup;
- }
-
- /**
- * Connect to the remote and call the printing function for
- * each of the remote references.
- */
- callbacks.credentials = cred_acquire_cb;
-
- error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL, NULL);
- if (error < 0)
- goto cleanup;
-
- /**
- * Get the list of references on the remote and print out
- * their name next to what they point to.
- */
- if (git_remote_ls(&refs, &refs_len, remote) < 0)
- goto cleanup;
-
- for (i = 0; i < refs_len; i++) {
- char oid[GIT_OID_HEXSZ + 1] = {0};
- git_oid_fmt(oid, &refs[i]->oid);
- printf("%s\t%s\n", oid, refs[i]->name);
- }
-
-cleanup:
- git_remote_free(remote);
- return error;
-}
-
-/** Entry point for this command */
-int ls_remote(git_repository *repo, int argc, char **argv)
-{
- int error;
-
- if (argc < 2) {
- fprintf(stderr, "usage: %s ls-remote <remote>\n", argv[-1]);
- return EXIT_FAILURE;
- }
-
- error = use_remote(repo, argv[1]);
-
- return error;
-}
--- /dev/null
+/*
+ * libgit2 "push" example - shows how to push to remote
+ *
+ * Written by the libgit2 contributors
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include "common.h"
+
+/**
+ * This example demonstrates the libgit2 push API to roughly
+ * simulate `git push`.
+ *
+ * This does not have:
+ *
+ * - Robust error handling
+ * - Any of the `git push` options
+ *
+ * This does have:
+ *
+ * - Example of push to origin/master
+ *
+ */
+
+/** Entry point for this command */
+int lg2_push(git_repository *repo, int argc, char **argv) {
+ git_push_options options;
+ git_remote* remote = NULL;
+ char *refspec = "refs/heads/master";
+ const git_strarray refspecs = {
+ &refspec,
+ 1
+ };
+
+ /* Validate args */
+ if (argc > 1) {
+ printf ("USAGE: %s\n\nsorry, no arguments supported yet\n", argv[0]);
+ return -1;
+ }
+
+ check_lg2(git_remote_lookup(&remote, repo, "origin" ), "Unable to lookup remote", NULL);
+
+ check_lg2(git_push_options_init(&options, GIT_PUSH_OPTIONS_VERSION ), "Error initializing push", NULL);
+
+ check_lg2(git_remote_push(remote, &refspecs, &options), "Error pushing", NULL);
+
+ printf("pushed\n");
+ return 0;
+}
subcmd_show,
};
-struct opts {
+struct remote_opts {
enum subcmd cmd;
/* for command-specific args */
char **argv;
};
-static int cmd_add(git_repository *repo, struct opts *o);
-static int cmd_remove(git_repository *repo, struct opts *o);
-static int cmd_rename(git_repository *repo, struct opts *o);
-static int cmd_seturl(git_repository *repo, struct opts *o);
-static int cmd_show(git_repository *repo, struct opts *o);
+static int cmd_add(git_repository *repo, struct remote_opts *o);
+static int cmd_remove(git_repository *repo, struct remote_opts *o);
+static int cmd_rename(git_repository *repo, struct remote_opts *o);
+static int cmd_seturl(git_repository *repo, struct remote_opts *o);
+static int cmd_show(git_repository *repo, struct remote_opts *o);
static void parse_subcmd(
- struct opts *opt, int argc, char **argv);
+ struct remote_opts *opt, int argc, char **argv);
static void usage(const char *msg, const char *arg);
-int main(int argc, char *argv[])
+int lg2_remote(git_repository *repo, int argc, char *argv[])
{
int retval = 0;
- struct opts opt = {0};
- git_buf buf = GIT_BUF_INIT_CONST(NULL, 0);
- git_repository *repo = NULL;
+ struct remote_opts opt = {0};
parse_subcmd(&opt, argc, argv);
- git_libgit2_init();
-
- check_lg2(git_repository_discover(&buf, ".", 0, NULL),
- "Could not find repository", NULL);
-
- check_lg2(git_repository_open(&repo, buf.ptr),
- "Could not open repository", NULL);
- git_buf_dispose(&buf);
-
switch (opt.cmd)
{
case subcmd_add:
break;
}
- git_libgit2_shutdown();
-
return retval;
}
-static int cmd_add(git_repository *repo, struct opts *o)
+static int cmd_add(git_repository *repo, struct remote_opts *o)
{
char *name, *url;
git_remote *remote = {0};
return 0;
}
-static int cmd_remove(git_repository *repo, struct opts *o)
+static int cmd_remove(git_repository *repo, struct remote_opts *o)
{
char *name;
return 0;
}
-static int cmd_rename(git_repository *repo, struct opts *o)
+static int cmd_rename(git_repository *repo, struct remote_opts *o)
{
int i, retval;
char *old, *new;
puts(problems.strings[0]);
}
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
return retval;
}
-static int cmd_seturl(git_repository *repo, struct opts *o)
+static int cmd_seturl(git_repository *repo, struct remote_opts *o)
{
int i, retval, push = 0;
char *name = NULL, *url = NULL;
return 0;
}
-static int cmd_show(git_repository *repo, struct opts *o)
+static int cmd_show(git_repository *repo, struct remote_opts *o)
{
int i;
const char *arg, *name, *fetch, *push;
git_remote_free(remote);
}
- git_strarray_free(&remotes);
+ git_strarray_dispose(&remotes);
return 0;
}
static void parse_subcmd(
- struct opts *opt, int argc, char **argv)
+ struct remote_opts *opt, int argc, char **argv)
{
char *arg = argv[1];
enum subcmd cmd = 0;
#include "common.h"
-static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts);
+#include <assert.h>
-int main (int argc, char **argv)
+static int revwalk_parse_options(git_sort_t *sort, struct args_info *args);
+static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args);
+
+int lg2_rev_list(git_repository *repo, int argc, char **argv)
{
- git_repository *repo;
+ struct args_info args = ARGS_INFO_INIT;
git_revwalk *walk;
git_oid oid;
+ git_sort_t sort;
char buf[GIT_OID_HEXSZ+1];
- git_libgit2_init();
+ check_lg2(revwalk_parse_options(&sort, &args), "parsing options", NULL);
- check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "opening repository", NULL);
check_lg2(git_revwalk_new(&walk, repo), "allocating revwalk", NULL);
- check_lg2(revwalk_parseopts(repo, walk, argc-1, argv+1), "parsing options", NULL);
+ git_revwalk_sorting(walk, sort);
+ check_lg2(revwalk_parse_revs(repo, walk, &args), "parsing revs", NULL);
while (!git_revwalk_next(&oid, walk)) {
git_oid_fmt(buf, &oid);
printf("%s\n", buf);
}
- git_libgit2_shutdown();
+ git_revwalk_free(walk);
return 0;
}
return error;
}
-static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts)
+static void print_usage(void)
+{
+ fprintf(stderr, "rev-list [--git-dir=dir] [--topo-order|--date-order] [--reverse] <revspec>\n");
+ exit(-1);
+}
+
+static int revwalk_parse_options(git_sort_t *sort, struct args_info *args)
+{
+ assert(sort && args);
+ *sort = GIT_SORT_NONE;
+
+ if (args->argc < 1)
+ print_usage();
+
+ for (args->pos = 1; args->pos < args->argc; ++args->pos) {
+ const char *curr = args->argv[args->pos];
+
+ if (!strcmp(curr, "--topo-order")) {
+ *sort |= GIT_SORT_TOPOLOGICAL;
+ } else if (!strcmp(curr, "--date-order")) {
+ *sort |= GIT_SORT_TIME;
+ } else if (!strcmp(curr, "--reverse")) {
+ *sort |= (*sort & ~GIT_SORT_REVERSE) ^ GIT_SORT_REVERSE;
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
+
+static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args)
{
- int hide, i, error;
- unsigned int sorting = GIT_SORT_NONE;
+ int hide, error;
+ git_oid oid;
hide = 0;
- for (i = 0; i < nopts; i++) {
- if (!strcmp(opts[i], "--topo-order")) {
- sorting = GIT_SORT_TOPOLOGICAL | (sorting & GIT_SORT_REVERSE);
- git_revwalk_sorting(walk, sorting);
- } else if (!strcmp(opts[i], "--date-order")) {
- sorting = GIT_SORT_TIME | (sorting & GIT_SORT_REVERSE);
- git_revwalk_sorting(walk, sorting);
- } else if (!strcmp(opts[i], "--reverse")) {
- sorting = (sorting & ~GIT_SORT_REVERSE)
- | ((sorting & GIT_SORT_REVERSE) ? 0 : GIT_SORT_REVERSE);
- git_revwalk_sorting(walk, sorting);
- } else if (!strcmp(opts[i], "--not")) {
+ for (; args->pos < args->argc; ++args->pos) {
+ const char *curr = args->argv[args->pos];
+
+ if (!strcmp(curr, "--not")) {
hide = !hide;
- } else if (opts[i][0] == '^') {
- if ((error = push_spec(repo, walk, opts[i] + 1, !hide)))
+ } else if (curr[0] == '^') {
+ if ((error = push_spec(repo, walk, curr + 1, !hide)))
return error;
- } else if (strstr(opts[i], "..")) {
- if ((error = push_range(repo, walk, opts[i], hide)))
+ } else if (strstr(curr, "..")) {
+ if ((error = push_range(repo, walk, curr, hide)))
return error;
} else {
- if ((error = push_spec(repo, walk, opts[i], hide)))
+ if (push_spec(repo, walk, curr, hide) == 0)
+ continue;
+
+ if ((error = git_oid_fromstr(&oid, curr)))
+ return error;
+ if ((error = push_commit(walk, &oid, hide)))
return error;
}
}
/** Forward declarations for helpers. */
struct parse_state {
- git_repository *repo;
const char *repodir;
const char *spec;
int not;
};
static void parse_opts(struct parse_state *ps, int argc, char *argv[]);
-static int parse_revision(struct parse_state *ps);
+static int parse_revision(git_repository *repo, struct parse_state *ps);
-
-int main(int argc, char *argv[])
+int lg2_rev_parse(git_repository *repo, int argc, char *argv[])
{
struct parse_state ps = {0};
- git_libgit2_init();
parse_opts(&ps, argc, argv);
- check_lg2(parse_revision(&ps), "Parsing", NULL);
-
- git_repository_free(ps.repo);
- git_libgit2_shutdown();
+ check_lg2(parse_revision(repo, &ps), "Parsing", NULL);
return 0;
}
}
}
-static int parse_revision(struct parse_state *ps)
+static int parse_revision(git_repository *repo, struct parse_state *ps)
{
git_revspec rs;
char str[GIT_OID_HEXSZ + 1];
- if (!ps->repo) {
- if (!ps->repodir)
- ps->repodir = ".";
- check_lg2(git_repository_open_ext(&ps->repo, ps->repodir, 0, NULL),
- "Could not open repository from", ps->repodir);
- }
-
- check_lg2(git_revparse(&rs, ps->repo, ps->spec), "Could not parse", ps->spec);
+ check_lg2(git_revparse(&rs, repo, ps->spec), "Could not parse", ps->spec);
if ((rs.flags & GIT_REVPARSE_SINGLE) != 0) {
git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
if ((rs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
git_oid base;
- check_lg2(git_merge_base(&base, ps->repo,
+ check_lg2(git_merge_base(&base, repo,
git_object_id(rs.from), git_object_id(rs.to)),
"Could not find merge base", ps->spec);
--- /dev/null
+/*
+ * libgit2 "showindex" example - shows how to extract data from the index
+ *
+ * Written by the libgit2 contributors
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include "common.h"
+
+int lg2_show_index(git_repository *repo, int argc, char **argv)
+{
+ git_index *index;
+ size_t i, ecount;
+ char *dir = ".";
+ size_t dirlen;
+ char out[GIT_OID_HEXSZ+1];
+ out[GIT_OID_HEXSZ] = '\0';
+
+ if (argc > 2)
+ fatal("usage: showindex [<repo-dir>]", NULL);
+ if (argc > 1)
+ dir = argv[1];
+
+ dirlen = strlen(dir);
+ if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) {
+ check_lg2(git_index_open(&index, dir), "could not open index", dir);
+ } else {
+ check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir);
+ check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL);
+ git_repository_free(repo);
+ }
+
+ git_index_read(index, 0);
+
+ ecount = git_index_entrycount(index);
+ if (!ecount)
+ printf("Empty index\n");
+
+ for (i = 0; i < ecount; ++i) {
+ const git_index_entry *e = git_index_get_byindex(index, i);
+
+ git_oid_fmt(out, &e->id);
+
+ printf("File Path: %s\n", e->path);
+ printf(" Stage: %d\n", git_index_entry_stage(e));
+ printf(" Blob SHA: %s\n", out);
+ printf("File Mode: %07o\n", e->mode);
+ printf("File Size: %d bytes\n", (int)e->file_size);
+ printf("Dev/Inode: %d/%d\n", (int)e->dev, (int)e->ino);
+ printf(" UID/GID: %d/%d\n", (int)e->uid, (int)e->gid);
+ printf(" ctime: %d\n", (int)e->ctime.seconds);
+ printf(" mtime: %d\n", (int)e->mtime.seconds);
+ printf("\n");
+ }
+
+ git_index_free(index);
+
+ return 0;
+}
+++ /dev/null
-/*
- * libgit2 "showindex" example - shows how to extract data from the index
- *
- * Written by the libgit2 contributors
- *
- * To the extent possible under law, the author(s) have dedicated all copyright
- * and related and neighboring rights to this software to the public domain
- * worldwide. This software is distributed without any warranty.
- *
- * You should have received a copy of the CC0 Public Domain Dedication along
- * with this software. If not, see
- * <http://creativecommons.org/publicdomain/zero/1.0/>.
- */
-
-#include "common.h"
-
-int main (int argc, char** argv)
-{
- git_index *index;
- unsigned int i, ecount;
- char *dir = ".";
- size_t dirlen;
- char out[GIT_OID_HEXSZ+1];
- out[GIT_OID_HEXSZ] = '\0';
-
- git_libgit2_init();
-
- if (argc > 2)
- fatal("usage: showindex [<repo-dir>]", NULL);
- if (argc > 1)
- dir = argv[1];
-
- dirlen = strlen(dir);
- if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) {
- check_lg2(git_index_open(&index, dir), "could not open index", dir);
- } else {
- git_repository *repo;
- check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir);
- check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL);
- git_repository_free(repo);
- }
-
- git_index_read(index, 0);
-
- ecount = git_index_entrycount(index);
- if (!ecount)
- printf("Empty index\n");
-
- for (i = 0; i < ecount; ++i) {
- const git_index_entry *e = git_index_get_byindex(index, i);
-
- git_oid_fmt(out, &e->id);
-
- printf("File Path: %s\n", e->path);
- printf(" Stage: %d\n", git_index_entry_stage(e));
- printf(" Blob SHA: %s\n", out);
- printf("File Mode: %07o\n", e->mode);
- printf("File Size: %d bytes\n", (int)e->file_size);
- printf("Dev/Inode: %d/%d\n", (int)e->dev, (int)e->ino);
- printf(" UID/GID: %d/%d\n", (int)e->uid, (int)e->gid);
- printf(" ctime: %d\n", (int)e->ctime.seconds);
- printf(" mtime: %d\n", (int)e->mtime.seconds);
- printf("\n");
- }
-
- git_index_free(index);
- git_libgit2_shutdown();
-
- return 0;
-}
--- /dev/null
+/*
+ * libgit2 "stash" example - shows how to use the stash API
+ *
+ * Written by the libgit2 contributors
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdarg.h>
+
+#include "common.h"
+
+enum subcmd {
+ SUBCMD_APPLY,
+ SUBCMD_LIST,
+ SUBCMD_POP,
+ SUBCMD_PUSH
+};
+
+struct opts {
+ enum subcmd cmd;
+ int argc;
+ char **argv;
+};
+
+static void usage(const char *fmt, ...)
+{
+ va_list ap;
+
+ fputs("usage: git stash list\n", stderr);
+ fputs(" or: git stash ( pop | apply )\n", stderr);
+ fputs(" or: git stash [push]\n", stderr);
+ fputs("\n", stderr);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+static void parse_subcommand(struct opts *opts, int argc, char *argv[])
+{
+ char *arg = (argc < 2) ? "push" : argv[1];
+ enum subcmd cmd;
+
+ if (!strcmp(arg, "apply")) {
+ cmd = SUBCMD_APPLY;
+ } else if (!strcmp(arg, "list")) {
+ cmd = SUBCMD_LIST;
+ } else if (!strcmp(arg, "pop")) {
+ cmd = SUBCMD_POP;
+ } else if (!strcmp(arg, "push")) {
+ cmd = SUBCMD_PUSH;
+ } else {
+ usage("invalid command %s", arg);
+ return;
+ }
+
+ opts->cmd = cmd;
+ opts->argc = (argc < 2) ? argc - 1 : argc - 2;
+ opts->argv = argv;
+}
+
+static int cmd_apply(git_repository *repo, struct opts *opts)
+{
+ if (opts->argc)
+ usage("apply does not accept any parameters");
+
+ check_lg2(git_stash_apply(repo, 0, NULL),
+ "Unable to apply stash", NULL);
+
+ return 0;
+}
+
+static int list_stash_cb(size_t index, const char *message,
+ const git_oid *stash_id, void *payload)
+{
+ UNUSED(stash_id);
+ UNUSED(payload);
+ printf("stash@{%"PRIuZ"}: %s\n", index, message);
+ return 0;
+}
+
+static int cmd_list(git_repository *repo, struct opts *opts)
+{
+ if (opts->argc)
+ usage("list does not accept any parameters");
+
+ check_lg2(git_stash_foreach(repo, list_stash_cb, NULL),
+ "Unable to list stashes", NULL);
+
+ return 0;
+}
+
+static int cmd_push(git_repository *repo, struct opts *opts)
+{
+ git_signature *signature;
+ git_commit *stash;
+ git_oid stashid;
+
+ if (opts->argc)
+ usage("push does not accept any parameters");
+
+ check_lg2(git_signature_default(&signature, repo),
+ "Unable to get signature", NULL);
+ check_lg2(git_stash_save(&stashid, repo, signature, NULL, GIT_STASH_DEFAULT),
+ "Unable to save stash", NULL);
+ check_lg2(git_commit_lookup(&stash, repo, &stashid),
+ "Unable to lookup stash commit", NULL);
+
+ printf("Saved working directory %s\n", git_commit_summary(stash));
+
+ git_signature_free(signature);
+ git_commit_free(stash);
+
+ return 0;
+}
+
+static int cmd_pop(git_repository *repo, struct opts *opts)
+{
+ if (opts->argc)
+ usage("pop does not accept any parameters");
+
+ check_lg2(git_stash_pop(repo, 0, NULL),
+ "Unable to pop stash", NULL);
+
+ printf("Dropped refs/stash@{0}\n");
+
+ return 0;
+}
+
+int lg2_stash(git_repository *repo, int argc, char *argv[])
+{
+ struct opts opts = { 0 };
+
+ parse_subcommand(&opts, argc, argv);
+
+ switch (opts.cmd) {
+ case SUBCMD_APPLY:
+ return cmd_apply(repo, &opts);
+ case SUBCMD_LIST:
+ return cmd_list(repo, &opts);
+ case SUBCMD_PUSH:
+ return cmd_push(repo, &opts);
+ case SUBCMD_POP:
+ return cmd_pop(repo, &opts);
+ }
+
+ return -1;
+}
*/
#include "common.h"
-#ifdef _WIN32
-# include <Windows.h>
-# define sleep(a) Sleep(a * 1000)
-#else
-# include <unistd.h>
-#endif
/**
* This example demonstrates the use of the libgit2 status APIs,
#define MAX_PATHSPEC 8
-struct opts {
+struct status_opts {
git_status_options statusopt;
char *repodir;
char *pathspec[MAX_PATHSPEC];
int repeat;
};
-static void parse_opts(struct opts *o, int argc, char *argv[]);
+static void parse_opts(struct status_opts *o, int argc, char *argv[]);
static void show_branch(git_repository *repo, int format);
static void print_long(git_status_list *status);
static void print_short(git_repository *repo, git_status_list *status);
static int print_submod(git_submodule *sm, const char *name, void *payload);
-int main(int argc, char *argv[])
+int lg2_status(git_repository *repo, int argc, char *argv[])
{
- git_repository *repo = NULL;
git_status_list *status;
- struct opts o = { GIT_STATUS_OPTIONS_INIT, "." };
-
- git_libgit2_init();
+ struct status_opts o = { GIT_STATUS_OPTIONS_INIT, "." };
o.statusopt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
o.statusopt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
parse_opts(&o, argc, argv);
- /**
- * Try to open the repository at the given path (or at the current
- * directory if none was given).
- */
- check_lg2(git_repository_open_ext(&repo, o.repodir, 0, NULL),
- "Could not open repository", o.repodir);
-
if (git_repository_is_bare(repo))
fatal("Cannot report status on bare repository",
git_repository_path(repo));
goto show_status;
}
- git_repository_free(repo);
- git_libgit2_shutdown();
-
return 0;
}
/**
* Parse options that git's status command supports.
*/
-static void parse_opts(struct opts *o, int argc, char *argv[])
+static void parse_opts(struct status_opts *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
*/
/** tag_options represents the parsed command line options */
-typedef struct {
+struct tag_options {
const char *message;
const char *pattern;
const char *tag_name;
const char *target;
int num_lines;
int force;
-} tag_options;
+};
/** tag_state represents the current program state for dragging around */
typedef struct {
git_repository *repo;
- tag_options *opts;
+ struct tag_options *opts;
} tag_state;
/** An action to execute based on the command line arguments */
each_tag(tag_names.strings[i], state);
}
- git_strarray_free(&tag_names);
+ git_strarray_dispose(&tag_names);
}
static void action_delete_tag(tag_state *state)
{
- tag_options *opts = state->opts;
+ struct tag_options *opts = state->opts;
git_object *obj;
git_buf abbrev_oid = {0};
static void action_create_lighweight_tag(tag_state *state)
{
git_repository *repo = state->repo;
- tag_options *opts = state->opts;
+ struct tag_options *opts = state->opts;
git_oid oid;
git_object *target;
static void action_create_tag(tag_state *state)
{
git_repository *repo = state->repo;
- tag_options *opts = state->opts;
+ struct tag_options *opts = state->opts;
git_signature *tagger;
git_oid oid;
git_object *target;
}
/** Parse command line arguments and choose action to run when done */
-static void parse_options(tag_action *action, tag_options *opts, int argc, char **argv)
+static void parse_options(tag_action *action, struct tag_options *opts, int argc, char **argv)
{
args_info args = ARGS_INFO_INIT;
*action = &action_list_tags;
}
/** Initialize tag_options struct */
-static void tag_options_init(tag_options *opts)
+static void tag_options_init(struct tag_options *opts)
{
memset(opts, 0, sizeof(*opts));
opts->force = 0;
}
-int main(int argc, char **argv)
+int lg2_tag(git_repository *repo, int argc, char **argv)
{
- git_repository *repo;
- tag_options opts;
+ struct tag_options opts;
tag_action action;
tag_state state;
- git_libgit2_init();
-
- check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
- "Could not open repository", NULL);
-
tag_options_init(&opts);
parse_options(&action, &opts, argc, argv);
state.opts = &opts;
action(&state);
- git_repository_free(repo);
- git_libgit2_shutdown();
-
return 0;
}
+++ /dev/null
-#!/bin/bash
-
-THIS_FILE="$(readlink -f "$0")"
-ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")"
-PROGRAM="$ROOT"/examples/rev-list
-LIBDIR="$ROOT"/build
-REPO="$ROOT"/tests/resources/testrepo.git
-
-cd "$REPO"
-
-run () {
- LD_LIBRARY_PATH="$LIBDIR" "$PROGRAM" "$@"
-}
-
-diff -u - <(run --date-order a4a7dce) <<EOF
-a4a7dce85cf63874e984719f4fdd239f5145052f
-c47800c7266a2be04c571c04d5a6614691ea99bd
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-8496071c1b46c854b31185ea97743be6a8774479
-EOF
-
-out="$(run --topo-order a4a7dce)"
-diff -q - <(echo -n "$out") <<EOF >/dev/null ||
-a4a7dce85cf63874e984719f4fdd239f5145052f
-c47800c7266a2be04c571c04d5a6614691ea99bd
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-8496071c1b46c854b31185ea97743be6a8774479
-EOF
-diff -u - <(echo "$out") <<EOF
-a4a7dce85cf63874e984719f4fdd239f5145052f
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-c47800c7266a2be04c571c04d5a6614691ea99bd
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-8496071c1b46c854b31185ea97743be6a8774479
-EOF
-
-diff -u - <(run --date-order --reverse a4a7dce) <<EOF
-8496071c1b46c854b31185ea97743be6a8774479
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-9fd738e8f7967c078dceed8190330fc8648ee56a
-c47800c7266a2be04c571c04d5a6614691ea99bd
-a4a7dce85cf63874e984719f4fdd239f5145052f
-EOF
-
-out=$(run --topo-order --reverse a4a7dce)
-diff -q - <(echo -n "$out") <<EOF >/dev/null ||
-8496071c1b46c854b31185ea97743be6a8774479
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-9fd738e8f7967c078dceed8190330fc8648ee56a
-c47800c7266a2be04c571c04d5a6614691ea99bd
-a4a7dce85cf63874e984719f4fdd239f5145052f
-EOF
-diff -u - <(echo "$out") <<EOF
-8496071c1b46c854b31185ea97743be6a8774479
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-c47800c7266a2be04c571c04d5a6614691ea99bd
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-9fd738e8f7967c078dceed8190330fc8648ee56a
-a4a7dce85cf63874e984719f4fdd239f5145052f
-EOF
-
-out="$(run --date-order --topo-order --reverse --reverse a4a7dce)"
-diff -q - <(echo -n "$out") <<EOF >/dev/null ||
-a4a7dce85cf63874e984719f4fdd239f5145052f
-c47800c7266a2be04c571c04d5a6614691ea99bd
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-8496071c1b46c854b31185ea97743be6a8774479
-EOF
-diff -u - <(echo "$out") <<EOF
-a4a7dce85cf63874e984719f4fdd239f5145052f
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-c47800c7266a2be04c571c04d5a6614691ea99bd
-5b5b025afb0b4c913b4c338a42934a3863bf3644
-8496071c1b46c854b31185ea97743be6a8774479
-EOF
-
-diff -u - <(run ^9fd738e~2 9fd738e) <<EOF
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-EOF
-
-diff -u - <(run --not 9fd738e..9fd738e~2) <<EOF
-9fd738e8f7967c078dceed8190330fc8648ee56a
-4a202b346bb0fb0db7eff3cffeb3c70babbd2045
-EOF
LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
+INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES})
IF(BUILD_FUZZERS AND NOT USE_STANDALONE_FUZZERS)
ADD_C_FLAG(-fsanitize=fuzzer)
FILE(GLOB SRC_FUZZ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *_fuzzer.c)
FOREACH(fuzz_target_src ${SRC_FUZZ})
STRING(REPLACE ".c" "" fuzz_target_name ${fuzz_target_src})
+ STRING(REPLACE "_fuzzer" "" fuzz_name ${fuzz_target_name})
+
SET(${fuzz_target_name}_SOURCES ${fuzz_target_src} ${LIBGIT2_OBJECTS})
IF(USE_STANDALONE_FUZZERS)
LIST(APPEND ${fuzz_target_name}_SOURCES "standalone_driver.c")
ADD_EXECUTABLE(${fuzz_target_name} ${${fuzz_target_name}_SOURCES})
SET_TARGET_PROPERTIES(${fuzz_target_name} PROPERTIES C_STANDARD 90)
TARGET_LINK_LIBRARIES(${fuzz_target_name} ${LIBGIT2_LIBS})
+
+ ADD_TEST(${fuzz_target_name} "${CMAKE_CURRENT_BINARY_DIR}/${fuzz_target_name}" "${CMAKE_CURRENT_SOURCE_DIR}/corpora/${fuzz_name}")
ENDFOREACH()
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <git2.h>
+#include "git2.h"
#include "config_backend.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <limits.h>
-#include <errno.h>
-
#define UNUSED(x) (void)(x)
int foreach_cb(const git_config_entry *entry, void *payload)
--- /dev/null
+ãM\ 2ÿãa
\ No newline at end of file
--- /dev/null
+ãü7
\ No newline at end of file
--- /dev/null
+ÃØseed
\ No newline at end of file
--- /dev/null
+ã\1a\1aH\ 4\e
\ No newline at end of file
--- /dev/null
+©*
\ No newline at end of file
--- /dev/null
+ãÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ\8aÛÛÛÛÛÛÛÛÛÛËÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛËÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
\ No newline at end of file
--- /dev/null
+ãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏ
\ No newline at end of file
--- /dev/null
+ãyyyyy\9a\9ayyyyyyyyÅÅ
\ No newline at end of file
--- /dev/null
+ðã½D
\ No newline at end of file
--- /dev/null
+ãïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï*ïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïéïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï\10\10\10\10\10
\ No newline at end of file
--- /dev/null
+ïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïñïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïçïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïÿÿÿÿ
\ No newline at end of file
--- /dev/null
+ã\ 1]]ÿÿÿÿ\ 1\ 5ÿÿ\es4
\ No newline at end of file
--- /dev/null
+ÿ&ã
+ÿÿ)Å
\ No newline at end of file
--- /dev/null
+ãÂë®<\99\93 V¨Ý`oÓ¤Ük\v@rÜshuffleéDHE-PSK-ARÿÿÿÿÿÿÿ'MIDÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛàÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ[ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
\ No newline at end of file
--- /dev/null
+ãÿÿÿÿÿÿÿïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïÿÿÿÿÿÿ\ 2Óïïïïïïïïïïïïïïïïïïïï÷ïïïïïï\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10ïïïïïÿ
\ No newline at end of file
--- /dev/null
+ãj
\ No newline at end of file
--- /dev/null
+\9b\14
\ No newline at end of file
--- /dev/null
+Ã
\ No newline at end of file
--- /dev/null
+Ñã
\ No newline at end of file
--- /dev/null
+ãðc½D
\ No newline at end of file
--- /dev/null
+Åç
\ No newline at end of file
--- /dev/null
+ãoÙ¬ÿÿ
\ No newline at end of file
--- /dev/null
+ãïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï;ïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï
\ No newline at end of file
--- /dev/null
+ãp
\ No newline at end of file
--- /dev/null
+ã
+yã
+y
\ No newline at end of file
--- /dev/null
+ã\ 1]]ÿÿÿÿ\ 1\ 5ÿ\es5e
\ No newline at end of file
--- /dev/null
+Ïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïïï
\ No newline at end of file
--- /dev/null
+\ 1diff --git a/fuzzers/patch_fuzzer.c b/fuzzers/patch_fuzzer.c
+index 76186b6fb..f7ce73ac8 100644
+--- a/fuzzers/patch_fuzzer.c
++++ b/fuzzers/patch_fuzzer.c
+@@ -32,7 +32,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+ git_patch* patch;
+ git_patch_options opts = {(uint32_t)data[0]};
+ int status = git_patch_from_buffer(&patch, (const char*)data+1, size-1, &opts);
+- if (status == 0 && patch) {
++ if (patch) {
+ git_patch_free(patch);
+ }
+ return 0;
--- /dev/null
+\ 1diff --git a/fuzzers/patch_fuzzer.c b/fuzzers/patch_fuzzer.c
+new file mode 100644
+index 000000000..76186b6fb
+--- /dev/null
++++ b/fuzzers/patch_fuzzer.c
+@@ -0,0 +1,39 @@
++/*
++ * libgit2 patch fuzzer target.
++ *
++ * Copyright (C) the libgit2 contributors. All rights reserved.
++ *
++ * This file is part of libgit2, distributed under the GNU GPL v2 with
++ * a Linking Exception. For full terms see the included COPYING file.
++ */
++
++#include "git2.h"
++#include "patch.h"
++#include "patch_parse.h"
++
++#define UNUSED(x) (void)(x)
++
++int LLVMFuzzerInitialize(int *argc, char ***argv)
++{
++ UNUSED(argc);
++ UNUSED(argv);
++
++ if (git_libgit2_init() < 0)
++ abort();
++
++ return 0;
++}
++
++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
++{
++ if (size < 1) {
++ return 0;
++ }
++ git_patch* patch;
++ git_patch_options opts = {(uint32_t)data[0]};
++ int status = git_patch_from_buffer(&patch, (const char*)data+1, size-1, &opts);
++ if (status == 0 && patch) {
++ git_patch_free(patch);
++ }
++ return 0;
++}
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
#include "git2.h"
#include "git2/sys/transport.h"
+#include "futils.h"
#define UNUSED(x) (void)(x)
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
- char tmp[] = "/tmp/git2.XXXXXX";
+#if defined(_WIN32)
+ char tmpdir[MAX_PATH], path[MAX_PATH];
- UNUSED(argc);
- UNUSED(argv);
+ if (GetTempPath((DWORD)sizeof(tmpdir), tmpdir) == 0)
+ abort();
+
+ if (GetTempFileName(tmpdir, "lg2", 1, path) == 0)
+ abort();
+
+ if (git_futils_mkdir(path, 0700, 0) < 0)
+ abort();
+#else
+ char path[] = "/tmp/git2.XXXXXX";
+
+ if (mkdtemp(path) != path)
+ abort();
+#endif
if (git_libgit2_init() < 0)
abort();
if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0)
abort();
- if (mkdtemp(tmp) != tmp)
- abort();
+ UNUSED(argc);
+ UNUSED(argv);
- if (git_repository_init(&repo, tmp, 1) < 0)
+ if (git_repository_init(&repo, path, 1) < 0)
fuzzer_git_abort("git_repository_init");
return 0;
--- /dev/null
+/*
+ * libgit2 multi-pack-index fuzzer target.
+ *
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include <stdio.h>
+
+#include "git2.h"
+
+#include "buffer.h"
+#include "common.h"
+#include "futils.h"
+#include "hash.h"
+#include "midx.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ GIT_UNUSED(argc);
+ GIT_UNUSED(argv);
+
+ if (git_libgit2_init() < 0) {
+ fprintf(stderr, "Failed to initialize libgit2\n");
+ abort();
+ }
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ git_midx_file idx = {{0}};
+ git_midx_entry e;
+ git_buf midx_buf = GIT_BUF_INIT;
+ git_oid oid = {{0}};
+ bool append_hash = false;
+
+ if (size < 4)
+ return 0;
+
+ /*
+ * If the first byte in the stream has the high bit set, append the
+ * SHA1 hash so that the packfile is somewhat valid.
+ */
+ append_hash = *data & 0x80;
+ /* Keep a 4-byte alignment to avoid unaligned accesses. */
+ data += 4;
+ size -= 4;
+
+ if (append_hash) {
+ if (git_buf_init(&midx_buf, size + sizeof(oid)) < 0)
+ goto cleanup;
+ if (git_hash_buf(&oid, data, size) < 0) {
+ fprintf(stderr, "Failed to compute the SHA1 hash\n");
+ abort();
+ }
+ memcpy(midx_buf.ptr, data, size);
+ memcpy(midx_buf.ptr + size, &oid, sizeof(oid));
+ } else {
+ git_buf_attach_notowned(&midx_buf, (char *)data, size);
+ }
+
+ if (git_midx_parse(&idx, (const unsigned char *)git_buf_cstr(&midx_buf), git_buf_len(&midx_buf)) < 0)
+ goto cleanup;
+
+ /* Search for any oid, just to exercise that codepath. */
+ if (git_midx_entry_find(&e, &idx, &oid, GIT_OID_HEXSZ) < 0)
+ goto cleanup;
+
+cleanup:
+ git_midx_close(&idx);
+ git_buf_dispose(&midx_buf);
+ return 0;
+}
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
-#include <limits.h>
-#include <unistd.h>
#include "git2.h"
#include "git2/sys/mempack.h"
-
-#define UNUSED(x) (void)(x)
+#include "common.h"
+#include "buffer.h"
static git_odb *odb = NULL;
static git_odb_backend *mempack = NULL;
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
- UNUSED(argc);
- UNUSED(argv);
+ GIT_UNUSED(argc);
+ GIT_UNUSED(argv);
+
if (git_libgit2_init() < 0) {
fprintf(stderr, "Failed to initialize libgit2\n");
abort();
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
+ git_indexer_progress stats = {0, 0};
git_indexer *indexer = NULL;
- git_transfer_progress stats = {0, 0};
+ git_buf path = GIT_BUF_INIT;
+ git_oid oid;
bool append_hash = false;
- git_oid id;
- char hash[GIT_OID_HEXSZ + 1] = {0};
- char path[PATH_MAX];
if (size == 0)
return 0;
}
git_mempack_reset(mempack);
- if (git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB) < 0) {
+ if (git_odb_write(&oid, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB) < 0) {
fprintf(stderr, "Failed to add an object to the odb\n");
abort();
}
if (git_indexer_append(indexer, data, size, &stats) < 0)
goto cleanup;
if (append_hash) {
- git_oid oid;
if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB) < 0) {
fprintf(stderr, "Failed to compute the SHA1 hash\n");
abort();
if (git_indexer_commit(indexer, &stats) < 0)
goto cleanup;
- /*
- * We made it! We managed to produce a valid packfile.
- * Let's clean it up.
- */
- git_oid_fmt(hash, git_indexer_hash(indexer));
- printf("Generated packfile %s\n", hash);
- snprintf(path, sizeof(path), "pack-%s.idx", hash);
- unlink(path);
- snprintf(path, sizeof(path), "pack-%s.pack", hash);
- unlink(path);
+ if (git_buf_printf(&path, "pack-%s.idx", git_oid_tostr_s(git_indexer_hash(indexer))) < 0)
+ goto cleanup;
+ p_unlink(git_buf_cstr(&path));
+
+ git_buf_clear(&path);
+
+ if (git_buf_printf(&path, "pack-%s.pack", git_oid_tostr_s(git_indexer_hash(indexer))) < 0)
+ goto cleanup;
+ p_unlink(git_buf_cstr(&path));
cleanup:
git_mempack_reset(mempack);
git_indexer_free(indexer);
+ git_buf_dispose(&path);
return 0;
}
--- /dev/null
+/*
+ * libgit2 patch parser fuzzer target.
+ *
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "git2.h"
+#include "patch.h"
+#include "patch_parse.h"
+
+#define UNUSED(x) (void)(x)
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ UNUSED(argc);
+ UNUSED(argv);
+
+ if (git_libgit2_init() < 0)
+ abort();
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (size) {
+ git_patch *patch = NULL;
+ git_patch_options opts = GIT_PATCH_OPTIONS_INIT;
+ opts.prefix_len = (uint32_t)data[0];
+ git_patch_from_buffer(&patch, (const char *)data + 1, size - 1,
+ &opts);
+ git_patch_free(patch);
+ }
+ return 0;
+}
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include <assert.h>
-#include <dirent.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
#include "git2.h"
-#include "fileops.h"
+#include "futils.h"
#include "path.h"
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
int error = 0;
if (git_futils_readbuffer(&buf, filename) < 0) {
- fprintf(stderr, "Failed to read %s: %m\n", filename);
+ fprintf(stderr, "Failed to read %s: %s\n", filename, git_error_last()->message);
error = -1;
goto exit;
}
LLVMFuzzerInitialize(&argc, &argv);
if (git_path_dirload(&corpus_files, argv[1], 0, 0x0) < 0) {
- fprintf(stderr, "Failed to scan corpus directory: %m\n");
+ fprintf(stderr, "Failed to scan corpus directory '%s': %s\n",
+ argv[1], git_error_last()->message);
error = -1;
goto exit;
}
#include "git2/blame.h"
#include "git2/branch.h"
#include "git2/buffer.h"
+#include "git2/cert.h"
#include "git2/checkout.h"
#include "git2/cherrypick.h"
#include "git2/clone.h"
#include "git2/commit.h"
#include "git2/common.h"
#include "git2/config.h"
+#include "git2/credential.h"
#include "git2/deprecated.h"
#include "git2/describe.h"
#include "git2/diff.h"
const git_oid *id);
/**
- * Creates a `git_annotated_comit` from a revision string.
+ * Creates a `git_annotated_commit` from a revision string.
*
* See `man gitrevisions`, or
* http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for
const git_diff_hunk *hunk,
void *payload);
+/** Flags controlling the behavior of git_apply */
+typedef enum {
+ /**
+ * Don't actually make changes, just test that the patch applies.
+ * This is the equivalent of `git apply --check`.
+ */
+ GIT_APPLY_CHECK = (1 << 0),
+} git_apply_flags_t;
+
/**
* Apply options structure
*
* Initialize with `GIT_APPLY_OPTIONS_INIT`. Alternatively, you can
- * use `git_apply_init_options`.
+ * use `git_apply_options_init`.
*
* @see git_apply_to_tree, git_apply
*/
typedef struct {
- unsigned int version;
+ unsigned int version; /**< The version */
+ /** When applying a patch, callback that will be made per delta (file). */
git_apply_delta_cb delta_cb;
+
+ /** When applying a patch, callback that will be made per hunk. */
git_apply_hunk_cb hunk_cb;
+
+ /** Payload passed to both delta_cb & hunk_cb. */
void *payload;
+
+ /** Bitmask of git_apply_flags_t */
+ unsigned int flags;
} git_apply_options;
#define GIT_APPLY_OPTIONS_VERSION 1
#define GIT_APPLY_OPTIONS_INIT {GIT_APPLY_OPTIONS_VERSION}
+GIT_EXTERN(int) git_apply_options_init(git_apply_options *opts, unsigned int version);
+
/**
* Apply a `git_diff` to a `git_tree`, and return the resulting image
* as an index.
git_diff *diff,
const git_apply_options *options);
+/** Possible application locations for git_apply */
typedef enum {
/**
* Apply the patch to the workdir, leaving the index untouched.
* Then for file `xyz.c` looking up attribute "foo" gives a value for
* which `GIT_ATTR_TRUE(value)` is true.
*/
-#define GIT_ATTR_TRUE(attr) (git_attr_value(attr) == GIT_ATTR_TRUE_T)
+#define GIT_ATTR_IS_TRUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_TRUE)
/**
* GIT_ATTR_FALSE checks if an attribute is set off. In core git
* Then for file `zyx.h` looking up attribute "foo" gives a value for
* which `GIT_ATTR_FALSE(value)` is true.
*/
-#define GIT_ATTR_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_FALSE_T)
+#define GIT_ATTR_IS_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_FALSE)
/**
* GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This
* file `onefile.rb` or looking up "bar" on any file will all give
* `GIT_ATTR_UNSPECIFIED(value)` of true.
*/
-#define GIT_ATTR_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_UNSPECIFIED_T)
+#define GIT_ATTR_IS_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_UNSPECIFIED)
/**
* GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as
* Given this, looking up "eol" for `onefile.txt` will give back the
* string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
*/
-#define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_T)
+#define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_STRING)
/**
* Possible states for an attribute
*/
typedef enum {
- GIT_ATTR_UNSPECIFIED_T = 0, /**< The attribute has been left unspecified */
- GIT_ATTR_TRUE_T, /**< The attribute has been set */
- GIT_ATTR_FALSE_T, /**< The attribute has been unset */
- GIT_ATTR_VALUE_T, /**< This attribute has a value */
-} git_attr_t;
+ GIT_ATTR_VALUE_UNSPECIFIED = 0, /**< The attribute has been left unspecified */
+ GIT_ATTR_VALUE_TRUE, /**< The attribute has been set */
+ GIT_ATTR_VALUE_FALSE, /**< The attribute has been unset */
+ GIT_ATTR_VALUE_STRING, /**< This attribute has a value */
+} git_attr_value_t;
/**
* Return the value type for a given attribute.
* @param attr The attribute
* @return the value type for the attribute
*/
-GIT_EXTERN(git_attr_t) git_attr_value(const char *attr);
+GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr);
/**
* Check attribute flags: Reading values from index and working directory.
#define GIT_ATTR_CHECK_INDEX_ONLY 2
/**
- * Check attribute flags: Using the system attributes file.
+ * Check attribute flags: controlling extended attribute behavior.
*
* Normally, attribute checks include looking in the /etc (or system
* equivalent) directory for a `gitattributes` file. Passing this
* flag will cause attribute checks to ignore that file.
+ * equivalent) directory for a `gitattributes` file. Passing the
+ * `GIT_ATTR_CHECK_NO_SYSTEM` flag will cause attribute checks to
+ * ignore that file.
+ *
+ * Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes
+ * from a `.gitattributes` file in the repository at the HEAD revision.
*/
-#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2)
+#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2)
+#define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3)
/**
* Look up the value of one git attribute for path.
* disk no longer match the cached contents of memory. This will cause
* the attributes files to be reloaded the next time that an attribute
* access function is called.
+ *
+ * @param repo The repository containing the gitattributes cache
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_attr_cache_flush(
+GIT_EXTERN(int) git_attr_cache_flush(
git_repository *repo);
/**
* to canonical real names and email addresses. The mailmap will be read
* from the working directory, or HEAD in a bare repository. */
GIT_BLAME_USE_MAILMAP = (1<<5),
+ /** Ignore whitespace differences */
+ GIT_BLAME_IGNORE_WHITESPACE = (1<<6),
} git_blame_flag_t;
/**
* Blame options structure
*
* Initialize with `GIT_BLAME_OPTIONS_INIT`. Alternatively, you can
- * use `git_blame_init_options`.
+ * use `git_blame_options_init`.
*
*/
typedef struct git_blame_options {
* @param version The struct version; pass `GIT_BLAME_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_blame_init_options(
+GIT_EXTERN(int) git_blame_options_init(
git_blame_options *opts,
unsigned int version);
* @param blob pointer to the blob
* @return size on bytes
*/
-GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob);
+GIT_EXTERN(git_object_size_t) git_blob_rawsize(const git_blob *blob);
+
+/**
+ * Flags to control the functionality of `git_blob_filter`.
+ */
+typedef enum {
+ /** When set, filters will not be applied to binary files. */
+ GIT_BLOB_FILTER_CHECK_FOR_BINARY = (1 << 0),
+
+ /**
+ * When set, filters will not load configuration from the
+ * system-wide `gitattributes` in `/etc` (or system equivalent).
+ */
+ GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES = (1 << 1),
+
+ /**
+ * When set, filters will be loaded from a `.gitattributes` file
+ * in the HEAD commit.
+ */
+ GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD = (1 << 2),
+} git_blob_filter_flag_t;
+
+/**
+ * The options used when applying filter options to a file.
+ */
+typedef struct {
+ int version;
+
+ /** Flags to control the filtering process, see `git_blob_filter_flag_t` above */
+ uint32_t flags;
+} git_blob_filter_options;
+
+#define GIT_BLOB_FILTER_OPTIONS_VERSION 1
+#define GIT_BLOB_FILTER_OPTIONS_INIT {GIT_BLOB_FILTER_OPTIONS_VERSION, GIT_BLOB_FILTER_CHECK_FOR_BINARY}
/**
* Get a buffer with the filtered content of a blob.
* @param out The git_buf to be filled in
* @param blob Pointer to the blob
* @param as_path Path used for file attribute lookups, etc.
- * @param check_for_binary_data Should this test if blob content contains
- * NUL bytes / looks like binary data before applying filters?
+ * @param opts Options to use for filtering the blob
* @return 0 on success or an error code
*/
-GIT_EXTERN(int) git_blob_filtered_content(
+GIT_EXTERN(int) git_blob_filter(
git_buf *out,
git_blob *blob,
const char *as_path,
- int check_for_binary_data);
+ git_blob_filter_options *opts);
/**
* Read a file from the working folder of a repository
* relative to the repository's working dir
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path);
+GIT_EXTERN(int) git_blob_create_from_workdir(git_oid *id, git_repository *repo, const char *relative_path);
/**
* Read a file from the filesystem and write its content
* @param path file from which the blob will be created
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path);
+GIT_EXTERN(int) git_blob_create_from_disk(git_oid *id, git_repository *repo, const char *path);
/**
* Create a stream to write a new blob into the object db
* This function may need to buffer the data on disk and will in
* general not be the right choice if you know the size of the data
* to write. If you have data in memory, use
- * `git_blob_create_frombuffer()`. If you do not, but know the size of
+ * `git_blob_create_from_buffer()`. If you do not, but know the size of
* the contents (and don't want/need to perform filtering), use
* `git_odb_open_wstream()`.
*
* Don't close this stream yourself but pass it to
- * `git_blob_create_fromstream_commit()` to commit the write to the
+ * `git_blob_create_from_stream_commit()` to commit the write to the
* object db and get the object id.
*
* If the `hintpath` parameter is filled, it will be used to determine
* to apply onto the content of the blob to be created.
* @return 0 or error code
*/
-GIT_EXTERN(int) git_blob_create_fromstream(
+GIT_EXTERN(int) git_blob_create_from_stream(
git_writestream **out,
git_repository *repo,
const char *hintpath);
* @param stream the stream to close
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_blob_create_fromstream_commit(
+GIT_EXTERN(int) git_blob_create_from_stream_commit(
git_oid *out,
git_writestream *stream);
* @param len length of the data
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_blob_create_frombuffer(
+GIT_EXTERN(int) git_blob_create_from_buffer(
git_oid *id, git_repository *repo, const void *buffer, size_t len);
/**
/**
* Delete an existing branch reference.
*
- * If the branch is successfully deleted, the passed reference
- * object will be invalidated. The reference must be freed manually
- * by the user.
+ * Note that if the deletion succeeds, the reference object will not
+ * be valid anymore, and should be freed immediately by the user using
+ * `git_reference_free()`.
*
* @param branch A valid reference representing a branch
* @return 0 on success, or an error code.
* The new branch name will be checked for validity.
* See `git_tag_create()` for rules about valid names.
*
+ * Note that if the move succeeds, the old reference object will not
+ + be valid anymore, and should be freed immediately by the user using
+ + `git_reference_free()`.
+ *
+ * @param out New reference object for the updated name.
+ *
* @param branch Current underlying reference of the branch.
*
* @param new_branch_name Target name of the branch once the move
* Lookup a branch by its name in a repository.
*
* The generated reference must be freed by the user.
- *
* The branch name will be checked for validity.
- * See `git_tag_create()` for rules about valid names.
*
- * @param out pointer to the looked-up branch reference
+ * @see git_tag_create for rules about valid names.
*
+ * @param out pointer to the looked-up branch reference
* @param repo the repository to look up the branch
- *
* @param branch_name Name of the branch to be looked-up;
* this name is validated for consistency.
- *
* @param branch_type Type of the considered branch. This should
* be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE.
*
git_branch_t branch_type);
/**
- * Return the name of the given local or remote branch.
+ * Get the branch name
+ *
+ * Given a reference object, this will check that it really is a branch (ie.
+ * it lives under "refs/heads/" or "refs/remotes/"), and return the branch part
+ * of it.
*
- * The name of the branch matches the definition of the name
- * for git_branch_lookup. That is, if the returned name is given
- * to git_branch_lookup() then the reference is returned that
- * was given to this function.
+ * @param out Pointer to the abbreviated reference name.
+ * Owned by ref, do not free.
*
- * @param out where the pointer of branch name is stored;
- * this is valid as long as the ref is not freed.
- * @param ref the reference ideally pointing to a branch
+ * @param ref A reference object, ideally pointing to a branch
*
- * @return 0 on success; otherwise an error code (e.g., if the
- * ref is no local or remote branch).
+ * @return 0 on success; GIT_EINVALID if the reference isn't either a local or
+ * remote branch, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_name(
const char **out,
const git_reference *ref);
/**
- * Return the reference supporting the remote tracking branch,
- * given a local branch reference.
+ * Get the upstream of a branch
*
- * @param out Pointer where to store the retrieved
- * reference.
+ * Given a reference, this will return a new reference object corresponding
+ * to its remote tracking branch. The reference must be a local branch.
*
+ * @see git_branch_upstream_name for details on the resolution.
+ *
+ * @param out Pointer where to store the retrieved reference.
* @param branch Current underlying reference of the branch.
*
* @return 0 on success; GIT_ENOTFOUND when no remote tracking
- * reference exists, otherwise an error code.
+ * reference exists, otherwise an error code.
*/
GIT_EXTERN(int) git_branch_upstream(
git_reference **out,
const git_reference *branch);
/**
- * Set the upstream configuration for a given local branch
+ * Set a branch's upstream branch
*
- * @param branch the branch to configure
+ * This will update the configuration to set the branch named `branch_name` as the upstream of `branch`.
+ * Pass a NULL name to unset the upstream information.
*
- * @param upstream_name remote-tracking or local branch to set as
- * upstream. Pass NULL to unset.
+ * @note the actual tracking reference must have been already created for the
+ * operation to succeed.
*
- * @return 0 or an error code
+ * @param branch the branch to configure
+ * @param branch_name remote-tracking or local branch to set as upstream.
+ *
+ * @return 0 on success; GIT_ENOTFOUND if there's no branch named `branch_name`
+ * or an error code
*/
-GIT_EXTERN(int) git_branch_set_upstream(git_reference *branch, const char *upstream_name);
+GIT_EXTERN(int) git_branch_set_upstream(
+ git_reference *branch,
+ const char *branch_name);
/**
- * Return the name of the reference supporting the remote tracking branch,
- * given the name of a local branch reference.
- *
- * @param out Pointer to the user-allocated git_buf which will be
- * filled with the name of the reference.
+ * Get the upstream name of a branch
*
- * @param repo the repository where the branches live
+ * Given a local branch, this will return its remote-tracking branch information,
+ * as a full reference name, ie. "feature/nice" would become
+ * "refs/remote/origin/feature/nice", depending on that branch's configuration.
*
+ * @param out the buffer into which the name will be written.
+ * @param repo the repository where the branches live.
* @param refname reference name of the local branch.
*
- * @return 0, GIT_ENOTFOUND when no remote tracking reference exists,
- * otherwise an error code.
+ * @return 0 on success, GIT_ENOTFOUND when no remote tracking reference exists,
+ * or an error code.
*/
GIT_EXTERN(int) git_branch_upstream_name(
git_buf *out,
const char *refname);
/**
- * Determine if the current local branch is pointed at by HEAD.
+ * Determine if HEAD points to the given branch
*
- * @param branch Current underlying reference of the branch.
+ * @param branch A reference to a local branch.
*
- * @return 1 if HEAD points at the branch, 0 if it isn't,
- * error code otherwise.
+ * @return 1 if HEAD points at the branch, 0 if it isn't, or a negative value
+ * as an error code.
*/
GIT_EXTERN(int) git_branch_is_head(
const git_reference *branch);
/**
- * Determine if the current branch is checked out in any linked
- * repository.
+ * Determine if any HEAD points to the current branch
*
- * @param branch Reference to the branch.
+ * This will iterate over all known linked repositories (usually in the form of
+ * worktrees) and report whether any HEAD is pointing at the current branch.
*
- * @return 1 if branch is checked out, 0 if it isn't,
- * error code otherwise.
+ * @param branch A reference to a local branch.
+ *
+ * @return 1 if branch is checked out, 0 if it isn't, an error code otherwise.
*/
GIT_EXTERN(int) git_branch_is_checked_out(
const git_reference *branch);
/**
- * Return the name of remote that the remote tracking branch belongs to.
+ * Find the remote name of a remote-tracking branch
*
- * @param out Pointer to the user-allocated git_buf which will be filled with the name of the remote.
+ * This will return the name of the remote whose fetch refspec is matching
+ * the given branch. E.g. given a branch "refs/remotes/test/master", it will
+ * extract the "test" part. If refspecs from multiple remotes match,
+ * the function will return GIT_EAMBIGUOUS.
*
+ * @param out The buffer into which the name will be written.
* @param repo The repository where the branch lives.
+ * @param refname complete name of the remote tracking branch.
*
- * @param canonical_branch_name name of the remote tracking branch.
- *
- * @return 0, GIT_ENOTFOUND
- * when no remote matching remote was found,
- * GIT_EAMBIGUOUS when the branch maps to several remotes,
- * otherwise an error code.
+ * @return 0 on success, GIT_ENOTFOUND when no matching remote was found,
+ * GIT_EAMBIGUOUS when the branch maps to several remotes,
+ * otherwise an error code.
*/
GIT_EXTERN(int) git_branch_remote_name(
git_buf *out,
git_repository *repo,
- const char *canonical_branch_name);
-
+ const char *refname);
/**
- * Retrieve the name of the upstream remote of a local branch
+ * Retrieve the upstream remote of a local branch
+ *
+ * This will return the currently configured "branch.*.remote" for a given
+ * branch. This branch must be local.
*
* @param buf the buffer into which to write the name
* @param repo the repository in which to look
* a block of memory they hold. In this case, libgit2 will not resize or
* free the memory, but will read from it as needed.
*
- * A `git_buf` is a public structure with three fields:
- *
- * - `ptr` points to the start of the allocated memory. If it is NULL,
- * then the `git_buf` is considered empty and libgit2 will feel free
- * to overwrite it with new data.
- *
- * - `size` holds the size (in bytes) of the data that is actually used.
- *
- * - `asize` holds the known total amount of allocated memory if the `ptr`
- * was allocated by libgit2. It may be larger than `size`. If `ptr`
- * was not allocated by libgit2 and should not be resized and/or freed,
- * then `asize` will be set to zero.
- *
* Some APIs may occasionally do something slightly unusual with a buffer,
* such as setting `ptr` to a value that was passed in by the user. In
* those cases, the behavior will be clearly documented by the API.
*/
typedef struct {
+ /**
+ * The buffer contents.
+ *
+ * `ptr` points to the start of the allocated memory. If it is NULL,
+ * then the `git_buf` is considered empty and libgit2 will feel free
+ * to overwrite it with new data.
+ */
char *ptr;
- size_t asize, size;
+
+ /**
+ * `asize` holds the known total amount of allocated memory if the `ptr`
+ * was allocated by libgit2. It may be larger than `size`. If `ptr`
+ * was not allocated by libgit2 and should not be resized and/or freed,
+ * then `asize` will be set to zero.
+ */
+ size_t asize;
+
+ /**
+ * `size` holds the size (in bytes) of the data that is actually used.
+ */
+ size_t size;
} git_buf;
/**
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_cert_h__
+#define INCLUDE_git_cert_h__
+
+#include "common.h"
+
+/**
+ * @file git2/cert.h
+ * @brief Git certificate objects
+ * @defgroup git_cert Certificate objects
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Type of host certificate structure that is passed to the check callback
+ */
+typedef enum git_cert_t {
+ /**
+ * No information about the certificate is available. This may
+ * happen when using curl.
+ */
+ GIT_CERT_NONE,
+ /**
+ * The `data` argument to the callback will be a pointer to
+ * the DER-encoded data.
+ */
+ GIT_CERT_X509,
+ /**
+ * The `data` argument to the callback will be a pointer to a
+ * `git_cert_hostkey` structure.
+ */
+ GIT_CERT_HOSTKEY_LIBSSH2,
+ /**
+ * The `data` argument to the callback will be a pointer to a
+ * `git_strarray` with `name:content` strings containing
+ * information about the certificate. This is used when using
+ * curl.
+ */
+ GIT_CERT_STRARRAY,
+} git_cert_t;
+
+/**
+ * Parent type for `git_cert_hostkey` and `git_cert_x509`.
+ */
+struct git_cert {
+ /**
+ * Type of certificate. A `GIT_CERT_` value.
+ */
+ git_cert_t cert_type;
+};
+
+/**
+ * Callback for the user's custom certificate checks.
+ *
+ * @param cert The host certificate
+ * @param valid Whether the libgit2 checks (OpenSSL or WinHTTP) think
+ * this certificate is valid
+ * @param host Hostname of the host libgit2 connected to
+ * @param payload Payload provided by the caller
+ * @return 0 to proceed with the connection, < 0 to fail the connection
+ * or > 0 to indicate that the callback refused to act and that
+ * the existing validity determination should be honored
+ */
+typedef int GIT_CALLBACK(git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload);
+
+/**
+ * Type of SSH host fingerprint
+ */
+typedef enum {
+ /** MD5 is available */
+ GIT_CERT_SSH_MD5 = (1 << 0),
+ /** SHA-1 is available */
+ GIT_CERT_SSH_SHA1 = (1 << 1),
+ /** SHA-256 is available */
+ GIT_CERT_SSH_SHA256 = (1 << 2),
+} git_cert_ssh_t;
+
+/**
+ * Hostkey information taken from libssh2
+ */
+typedef struct {
+ git_cert parent; /**< The parent cert */
+
+ /**
+ * A hostkey type from libssh2, either
+ * `GIT_CERT_SSH_MD5` or `GIT_CERT_SSH_SHA1`
+ */
+ git_cert_ssh_t type;
+
+ /**
+ * Hostkey hash. If type has `GIT_CERT_SSH_MD5` set, this will
+ * have the MD5 hash of the hostkey.
+ */
+ unsigned char hash_md5[16];
+
+ /**
+ * Hostkey hash. If type has `GIT_CERT_SSH_SHA1` set, this will
+ * have the SHA-1 hash of the hostkey.
+ */
+ unsigned char hash_sha1[20];
+
+ /**
+ * Hostkey hash. If type has `GIT_CERT_SSH_SHA256` set, this will
+ * have the SHA-256 hash of the hostkey.
+ */
+ unsigned char hash_sha256[32];
+} git_cert_hostkey;
+
+/**
+ * X.509 certificate information
+ */
+typedef struct {
+ git_cert parent; /**< The parent cert */
+
+ /**
+ * Pointer to the X.509 certificate data
+ */
+ void *data;
+
+ /**
+ * Length of the memory block pointed to by `data`.
+ */
+ size_t len;
+} git_cert_x509;
+
+/** @} */
+GIT_END_DECL
+#endif
typedef enum {
GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */
- /** Allow safe updates that cannot overwrite uncommitted data */
+ /**
+ * Allow safe updates that cannot overwrite uncommitted data.
+ * If the uncommitted changes don't conflict with the checked out files,
+ * the checkout will still proceed, leaving the changes intact.
+ *
+ * Mutually exclusive with GIT_CHECKOUT_FORCE.
+ * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE.
+ */
GIT_CHECKOUT_SAFE = (1u << 0),
- /** Allow all updates to force working directory to look like index */
+ /**
+ * Allow all updates to force working directory to look like index.
+ *
+ * Mutually exclusive with GIT_CHECKOUT_SAFE.
+ * GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE.
+ */
GIT_CHECKOUT_FORCE = (1u << 1),
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu
} git_checkout_notify_t;
+/** Checkout performance-reporting structure */
typedef struct {
size_t mkdir_calls;
size_t stat_calls;
* Checkout options structure
*
* Initialize with `GIT_CHECKOUT_OPTIONS_INIT`. Alternatively, you can
- * use `git_checkout_init_options`.
+ * use `git_checkout_options_init`.
*
*/
typedef struct git_checkout_options {
- unsigned int version;
+ unsigned int version; /**< The version */
unsigned int checkout_strategy; /**< default will be a safe checkout */
int file_open_flags; /**< default is O_CREAT | O_TRUNC | O_WRONLY */
unsigned int notify_flags; /**< see `git_checkout_notify_t` above */
+
+ /**
+ * Optional callback to get notifications on specific file states.
+ * @see git_checkout_notify_t
+ */
git_checkout_notify_cb notify_cb;
+
+ /** Payload passed to notify_cb */
void *notify_payload;
/** Optional callback to notify the consumer of checkout progress. */
git_checkout_progress_cb progress_cb;
+
+ /** Payload passed to progress_cb */
void *progress_payload;
- /** When not zeroed out, array of fnmatch patterns specifying which
- * paths should be taken into account, otherwise all files. Use
- * GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as simple list.
+ /**
+ * A list of wildmatch patterns or paths.
+ *
+ * By default, all paths are processed. If you pass an array of wildmatch
+ * patterns, those will be used to filter which paths should be taken into
+ * account.
+ *
+ * Use GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as a simple list.
*/
git_strarray paths;
- /** The expected content of the working directory; defaults to HEAD.
- * If the working directory does not match this baseline information,
- * that will produce a checkout conflict.
+ /**
+ * The expected content of the working directory; defaults to HEAD.
+ *
+ * If the working directory does not match this baseline information,
+ * that will produce a checkout conflict.
*/
git_tree *baseline;
- /** Like `baseline` above, though expressed as an index. This
- * option overrides `baseline`.
+ /**
+ * Like `baseline` above, though expressed as an index. This
+ * option overrides `baseline`.
*/
- git_index *baseline_index; /**< expected content of workdir, expressed as an index. */
+ git_index *baseline_index;
const char *target_directory; /**< alternative checkout path to workdir */
/** Optional callback to notify the consumer of performance data. */
git_checkout_perfdata_cb perfdata_cb;
+
+ /** Payload passed to perfdata_cb */
void *perfdata_payload;
} git_checkout_options;
* @param version The struct version; pass `GIT_CHECKOUT_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_checkout_init_options(
+GIT_EXTERN(int) git_checkout_options_init(
git_checkout_options *opts,
unsigned int version);
* @param version The struct version; pass `GIT_CHERRYPICK_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_cherrypick_init_options(
+GIT_EXTERN(int) git_cherrypick_options_init(
git_cherrypick_options *opts,
unsigned int version);
* @param out pointer to store the index result in
* @param repo the repository that contains the given commits
* @param cherrypick_commit the commit to cherry-pick
- * @param our_commit the commit to revert against (eg, HEAD)
- * @param mainline the parent of the revert commit, if it is a merge
+ * @param our_commit the commit to cherry-pick against (eg, HEAD)
+ * @param mainline the parent of the `cherrypick_commit`, if it is a merge
* @param merge_options the merge options (or null for defaults)
* @return zero on success, -1 on failure.
*/
* Clone options structure
*
* Initialize with `GIT_CLONE_OPTIONS_INIT`. Alternatively, you can
- * use `git_clone_init_options`.
+ * use `git_clone_options_init`.
*
*/
typedef struct git_clone_options {
* @param version The struct version; pass `GIT_CLONE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_clone_init_options(
+GIT_EXTERN(int) git_clone_options_init(
git_clone_options *opts,
unsigned int version);
*
* @param out the resulting commit id
* @param commit_content the content of the unsigned commit object
- * @param signature the signature to add to the commit
+ * @param signature the signature to add to the commit. Leave `NULL`
+ * to create a commit without adding a signature field.
* @param signature_field which header field should contain this
* signature. Leave `NULL` for the default of "gpgsig"
* @return 0 or an error code
*/
GIT_EXTERN(int) git_commit_dup(git_commit **out, git_commit *source);
+/**
+ * Commit signing callback.
+ *
+ * The callback will be called with the commit content, giving a user an
+ * opportunity to sign the commit content. The signature_field
+ * buf may be left empty to specify the default field "gpgsig".
+ *
+ * Signatures can take the form of any string, and can be created on an arbitrary
+ * header field. Signatures are most commonly used for verifying authorship of a
+ * commit using GPG or a similar cryptographically secure signing algorithm.
+ * See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for more
+ * details.
+ *
+ * When the callback:
+ * - returns GIT_PASSTHROUGH, no signature will be added to the commit.
+ * - returns < 0, commit creation will be aborted.
+ * - returns GIT_OK, the signature parameter is expected to be filled.
+ */
+typedef int (*git_commit_signing_cb)(
+ git_buf *signature, git_buf *signature_field, const char *commit_content, void *payload);
+
/** @} */
GIT_END_DECL
#endif
#endif
#if defined(_MSC_VER) && _MSC_VER < 1800
- GIT_BEGIN_DECL
-# include "inttypes.h"
- GIT_END_DECL
-/** This check is needed for importing this file in an iOS/OS X framework throws an error in Xcode otherwise.*/
+# include <stdint.h>
#elif !defined(__CLANG_INTTYPES_H)
# include <inttypes.h>
#endif
* @param major Store the major version number
* @param minor Store the minor version number
* @param rev Store the revision (patch) number
+ * @return 0 on success or an error code on failure
*/
-GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
+GIT_EXTERN(int) git_libgit2_version(int *major, int *minor, int *rev);
/**
* Combinations of these values describe the features with which libgit2
GIT_OPT_SET_ALLOCATOR,
GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY,
GIT_OPT_GET_PACK_MAX_OBJECTS,
- GIT_OPT_SET_PACK_MAX_OBJECTS
+ GIT_OPT_SET_PACK_MAX_OBJECTS,
+ GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS,
+ GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE,
+ GIT_OPT_GET_MWINDOW_FILE_LIMIT,
+ GIT_OPT_SET_MWINDOW_FILE_LIMIT
} git_libgit2_opt_t;
/**
*
* * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t):
*
- * >Set the maximum amount of memory that can be mapped at any time
- * by the library
+ * > Set the maximum amount of memory that can be mapped at any time
+ * > by the library
+ *
+ * * opts(GIT_OPT_GET_MWINDOW_FILE_LIMIT, size_t *):
+ *
+ * > Get the maximum number of files that will be mapped at any time by the
+ * > library
+ *
+ * * opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, size_t):
+ *
+ * > Set the maximum number of files that can be mapped at any time
+ * > by the library. The default (0) is unlimited.
*
* * opts(GIT_OPT_GET_SEARCH_PATH, int level, git_buf *buf)
*
* > Set the maximum number of objects libgit2 will allow in a pack
* > file when downloading a pack file from a remote.
*
+ * opts(GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, int enabled)
+ * > This will cause .keep file existence checks to be skipped when
+ * > accessing packfiles, which can help performance with remote filesystems.
+ *
+ * opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, int enabled)
+ * > When connecting to a server using NTLM or Negotiate
+ * > authentication, use expect/continue when POSTing data.
+ * > This option is not available on Windows.
+ *
* @param option Option key
* @param ... value to set the option
* @return 0 on success, <0 on failure
* Config var type
*/
typedef enum {
- GIT_CVAR_FALSE = 0,
- GIT_CVAR_TRUE = 1,
- GIT_CVAR_INT32,
- GIT_CVAR_STRING
-} git_cvar_t;
+ GIT_CONFIGMAP_FALSE = 0,
+ GIT_CONFIGMAP_TRUE = 1,
+ GIT_CONFIGMAP_INT32,
+ GIT_CONFIGMAP_STRING
+} git_configmap_t;
/**
* Mapping from config variables to values.
*/
typedef struct {
- git_cvar_t cvar_type;
+ git_configmap_t type;
const char *str_match;
int map_value;
-} git_cvar_map;
+} git_configmap;
/**
* Locate the path to the global configuration file
*
* A mapping array looks as follows:
*
- * git_cvar_map autocrlf_mapping[] = {
+ * git_configmap autocrlf_mapping[] = {
* {GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
* {GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
* {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT},
* @param out place to store the result of the mapping
* @param cfg config file to get the variables from
* @param name name of the config variable to lookup
- * @param maps array of `git_cvar_map` objects specifying the possible mappings
+ * @param maps array of `git_configmap` objects specifying the possible mappings
* @param map_n number of mapping objects in `maps`
* @return 0 on success, error code otherwise
*/
int *out,
const git_config *cfg,
const char *name,
- const git_cvar_map *maps,
+ const git_configmap *maps,
size_t map_n);
/**
* Maps a string value to an integer constant
*
* @param out place to store the result of the parsing
- * @param maps array of `git_cvar_map` objects specifying the possible mappings
+ * @param maps array of `git_configmap` objects specifying the possible mappings
* @param map_n number of mapping objects in `maps`
* @param value value to parse
*/
GIT_EXTERN(int) git_config_lookup_map_value(
int *out,
- const git_cvar_map *maps,
+ const git_configmap *maps,
size_t map_n,
const char *value);
#ifndef INCLUDE_git_cred_helpers_h__
#define INCLUDE_git_cred_helpers_h__
-#include "transport.h"
-
-/**
- * @file git2/cred_helpers.h
- * @brief Utility functions for credential management
- * @defgroup git_cred_helpers credential management helpers
- * @ingroup Git
- * @{
- */
-GIT_BEGIN_DECL
-
-/**
- * Payload for git_cred_stock_userpass_plaintext.
- */
-typedef struct git_cred_userpass_payload {
- const char *username;
- const char *password;
-} git_cred_userpass_payload;
-
-
-/**
- * Stock callback usable as a git_cred_acquire_cb. This calls
- * git_cred_userpass_plaintext_new unless the protocol has not specified
- * `GIT_CREDTYPE_USERPASS_PLAINTEXT` as an allowed type.
- *
- * @param cred The newly created credential object.
- * @param url The resource for which we are demanding a credential.
- * @param user_from_url The username that was embedded in a "user\@host"
- * remote url, or NULL if not included.
- * @param allowed_types A bitmask stating which cred types are OK to return.
- * @param payload The payload provided when specifying this callback. (This is
- * interpreted as a `git_cred_userpass_payload*`.)
- */
-GIT_EXTERN(int) git_cred_userpass(
- git_cred **cred,
- const char *url,
- const char *user_from_url,
- unsigned int allowed_types,
- void *payload);
-
+/* These declarations have moved. */
+#ifndef GIT_DEPRECATE_HARD
+# include "git2/credential_helpers.h"
+#endif
-/** @} */
-GIT_END_DECL
#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_credential_h__
+#define INCLUDE_git_credential_h__
+
+#include "common.h"
+
+/**
+ * @file git2/credential.h
+ * @brief Git authentication & credential management
+ * @defgroup git_credential Authentication & credential management
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Supported credential types
+ *
+ * This represents the various types of authentication methods supported by
+ * the library.
+ */
+typedef enum {
+ /**
+ * A vanilla user/password request
+ * @see git_credential_userpass_plaintext_new
+ */
+ GIT_CREDENTIAL_USERPASS_PLAINTEXT = (1u << 0),
+
+ /**
+ * An SSH key-based authentication request
+ * @see git_credential_ssh_key_new
+ */
+ GIT_CREDENTIAL_SSH_KEY = (1u << 1),
+
+ /**
+ * An SSH key-based authentication request, with a custom signature
+ * @see git_credential_ssh_custom_new
+ */
+ GIT_CREDENTIAL_SSH_CUSTOM = (1u << 2),
+
+ /**
+ * An NTLM/Negotiate-based authentication request.
+ * @see git_credential_default
+ */
+ GIT_CREDENTIAL_DEFAULT = (1u << 3),
+
+ /**
+ * An SSH interactive authentication request
+ * @see git_credential_ssh_interactive_new
+ */
+ GIT_CREDENTIAL_SSH_INTERACTIVE = (1u << 4),
+
+ /**
+ * Username-only authentication request
+ *
+ * Used as a pre-authentication step if the underlying transport
+ * (eg. SSH, with no username in its URL) does not know which username
+ * to use.
+ *
+ * @see git_credential_username_new
+ */
+ GIT_CREDENTIAL_USERNAME = (1u << 5),
+
+ /**
+ * An SSH key-based authentication request
+ *
+ * Allows credentials to be read from memory instead of files.
+ * Note that because of differences in crypto backend support, it might
+ * not be functional.
+ *
+ * @see git_credential_ssh_key_memory_new
+ */
+ GIT_CREDENTIAL_SSH_MEMORY = (1u << 6),
+} git_credential_t;
+
+/**
+ * The base structure for all credential types
+ */
+typedef struct git_credential git_credential;
+
+typedef struct git_credential_userpass_plaintext git_credential_userpass_plaintext;
+
+/** Username-only credential information */
+typedef struct git_credential_username git_credential_username;
+
+/** A key for NTLM/Kerberos "default" credentials */
+typedef struct git_credential git_credential_default;
+
+/**
+ * A ssh key from disk
+ */
+typedef struct git_credential_ssh_key git_credential_ssh_key;
+
+/**
+ * Keyboard-interactive based ssh authentication
+ */
+typedef struct git_credential_ssh_interactive git_credential_ssh_interactive;
+
+/**
+ * A key with a custom signature function
+ */
+typedef struct git_credential_ssh_custom git_credential_ssh_custom;
+
+/**
+ * Credential acquisition callback.
+ *
+ * This callback is usually involved any time another system might need
+ * authentication. As such, you are expected to provide a valid
+ * git_credential object back, depending on allowed_types (a
+ * git_credential_t bitmask).
+ *
+ * Note that most authentication details are your responsibility - this
+ * callback will be called until the authentication succeeds, or you report
+ * an error. As such, it's easy to get in a loop if you fail to stop providing
+ * the same incorrect credentials.
+ *
+ * @param out The newly created credential object.
+ * @param url The resource for which we are demanding a credential.
+ * @param username_from_url The username that was embedded in a "user\@host"
+ * remote url, or NULL if not included.
+ * @param allowed_types A bitmask stating which credential types are OK to return.
+ * @param payload The payload provided when specifying this callback.
+ * @return 0 for success, < 0 to indicate an error, > 0 to indicate
+ * no credential was acquired
+ */
+typedef int GIT_CALLBACK(git_credential_acquire_cb)(
+ git_credential **out,
+ const char *url,
+ const char *username_from_url,
+ unsigned int allowed_types,
+ void *payload);
+
+/**
+ * Free a credential.
+ *
+ * This is only necessary if you own the object; that is, if you are a
+ * transport.
+ *
+ * @param cred the object to free
+ */
+GIT_EXTERN(void) git_credential_free(git_credential *cred);
+
+/**
+ * Check whether a credential object contains username information.
+ *
+ * @param cred object to check
+ * @return 1 if the credential object has non-NULL username, 0 otherwise
+ */
+GIT_EXTERN(int) git_credential_has_username(git_credential *cred);
+
+/**
+ * Return the username associated with a credential object.
+ *
+ * @param cred object to check
+ * @return the credential username, or NULL if not applicable
+ */
+GIT_EXTERN(const char *) git_credential_get_username(git_credential *cred);
+
+/**
+ * Create a new plain-text username and password credential object.
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param out The newly created credential object.
+ * @param username The username of the credential.
+ * @param password The password of the credential.
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_userpass_plaintext_new(
+ git_credential **out,
+ const char *username,
+ const char *password);
+
+/**
+ * Create a "default" credential usable for Negotiate mechanisms like NTLM
+ * or Kerberos authentication.
+ *
+ * @param out The newly created credential object.
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_default_new(git_credential **out);
+
+/**
+ * Create a credential to specify a username.
+ *
+ * This is used with ssh authentication to query for the username if
+ * none is specified in the url.
+ *
+ * @param out The newly created credential object.
+ * @param username The username to authenticate with
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_username_new(git_credential **out, const char *username);
+
+/**
+ * Create a new passphrase-protected ssh key credential object.
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param out The newly created credential object.
+ * @param username username to use to authenticate
+ * @param publickey The path to the public key of the credential.
+ * @param privatekey The path to the private key of the credential.
+ * @param passphrase The passphrase of the credential.
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_ssh_key_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase);
+
+/**
+ * Create a new ssh key credential object reading the keys from memory.
+ *
+ * @param out The newly created credential object.
+ * @param username username to use to authenticate.
+ * @param publickey The public key of the credential.
+ * @param privatekey The private key of the credential.
+ * @param passphrase The passphrase of the credential.
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_ssh_key_memory_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase);
+
+/*
+ * If the user hasn't included libssh2.h before git2.h, we need to
+ * define a few types for the callback signatures.
+ */
+#ifndef LIBSSH2_VERSION
+typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
+typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT LIBSSH2_USERAUTH_KBDINT_PROMPT;
+typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE LIBSSH2_USERAUTH_KBDINT_RESPONSE;
+#endif
+
+typedef void GIT_CALLBACK(git_credential_ssh_interactive_cb)(
+ const char *name,
+ int name_len,
+ const char *instruction, int instruction_len,
+ int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
+ LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
+ void **abstract);
+
+
+/**
+ * Create a new ssh keyboard-interactive based credential object.
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param username Username to use to authenticate.
+ * @param prompt_callback The callback method used for prompts.
+ * @param payload Additional data to pass to the callback.
+ * @return 0 for success or an error code for failure.
+ */
+GIT_EXTERN(int) git_credential_ssh_interactive_new(
+ git_credential **out,
+ const char *username,
+ git_credential_ssh_interactive_cb prompt_callback,
+ void *payload);
+
+/**
+ * Create a new ssh key credential object used for querying an ssh-agent.
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param out The newly created credential object.
+ * @param username username to use to authenticate
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_ssh_key_from_agent(
+ git_credential **out,
+ const char *username);
+
+typedef int GIT_CALLBACK(git_credential_sign_cb)(
+ LIBSSH2_SESSION *session,
+ unsigned char **sig, size_t *sig_len,
+ const unsigned char *data, size_t data_len,
+ void **abstract);
+
+/**
+ * Create an ssh key credential with a custom signing function.
+ *
+ * This lets you use your own function to sign the challenge.
+ *
+ * This function and its credential type is provided for completeness
+ * and wraps `libssh2_userauth_publickey()`, which is undocumented.
+ *
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param out The newly created credential object.
+ * @param username username to use to authenticate
+ * @param publickey The bytes of the public key.
+ * @param publickey_len The length of the public key in bytes.
+ * @param sign_callback The callback method to sign the data during the challenge.
+ * @param payload Additional data to pass to the callback.
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_credential_ssh_custom_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ size_t publickey_len,
+ git_credential_sign_cb sign_callback,
+ void *payload);
+
+/** @} */
+GIT_END_DECL
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_credential_helpers_h__
+#define INCLUDE_git_credential_helpers_h__
+
+#include "transport.h"
+
+/**
+ * @file git2/credential_helpers.h
+ * @brief Utility functions for credential management
+ * @defgroup git_credential_helpers credential management helpers
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Payload for git_credential_userpass_plaintext.
+ */
+typedef struct git_credential_userpass_payload {
+ const char *username;
+ const char *password;
+} git_credential_userpass_payload;
+
+
+/**
+ * Stock callback usable as a git_credential_acquire_cb. This calls
+ * git_cred_userpass_plaintext_new unless the protocol has not specified
+ * `GIT_CREDENTIAL_USERPASS_PLAINTEXT` as an allowed type.
+ *
+ * @param out The newly created credential object.
+ * @param url The resource for which we are demanding a credential.
+ * @param user_from_url The username that was embedded in a "user\@host"
+ * remote url, or NULL if not included.
+ * @param allowed_types A bitmask stating which credential types are OK to return.
+ * @param payload The payload provided when specifying this callback. (This is
+ * interpreted as a `git_credential_userpass_payload*`.)
+ */
+GIT_EXTERN(int) git_credential_userpass(
+ git_credential **out,
+ const char *url,
+ const char *user_from_url,
+ unsigned int allowed_types,
+ void *payload);
+
+/** @} */
+GIT_END_DECL
+#endif
#ifndef INCLUDE_git_deprecated_h__
#define INCLUDE_git_deprecated_h__
+#include "attr.h"
+#include "config.h"
#include "common.h"
+#include "blame.h"
#include "buffer.h"
+#include "checkout.h"
+#include "cherrypick.h"
+#include "clone.h"
+#include "describe.h"
+#include "diff.h"
#include "errors.h"
#include "index.h"
+#include "indexer.h"
+#include "merge.h"
#include "object.h"
+#include "proxy.h"
#include "refs.h"
+#include "rebase.h"
+#include "remote.h"
+#include "trace.h"
+#include "repository.h"
+#include "revert.h"
+#include "stash.h"
+#include "status.h"
+#include "submodule.h"
+#include "worktree.h"
+#include "credential.h"
+#include "credential_helpers.h"
/*
* Users can avoid deprecated functions by defining `GIT_DEPRECATE_HARD`.
*/
#ifndef GIT_DEPRECATE_HARD
+/*
+ * The credential structures are now opaque by default, and their
+ * definition has moved into the `sys/credential.h` header; include
+ * them here for backward compatibility.
+ */
+#include "sys/credential.h"
+
/**
* @file git2/deprecated.h
* @brief libgit2 deprecated functions and values
*/
GIT_BEGIN_DECL
+/** @name Deprecated Attribute Constants
+ *
+ * These enumeration values are retained for backward compatibility.
+ * The newer versions of these functions should be preferred in all
+ * new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+#define GIT_ATTR_UNSPECIFIED_T GIT_ATTR_VALUE_UNSPECIFIED
+#define GIT_ATTR_TRUE_T GIT_ATTR_VALUE_TRUE
+#define GIT_ATTR_FALSE_T GIT_ATTR_VALUE_FALSE
+#define GIT_ATTR_VALUE_T GIT_ATTR_VALUE_STRING
+
+#define GIT_ATTR_TRUE(attr) GIT_ATTR_IS_TRUE(attr)
+#define GIT_ATTR_FALSE(attr) GIT_ATTR_IS_FALSE(attr)
+#define GIT_ATTR_UNSPECIFIED(attr) GIT_ATTR_IS_UNSPECIFIED(attr)
+
+typedef git_attr_value_t git_attr_t;
+
+/**@}*/
+
+/** @name Deprecated Blob Functions
+ *
+ * These functions are retained for backward compatibility. The newer
+ * versions of these functions should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path);
+GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path);
+GIT_EXTERN(int) git_blob_create_fromstream(
+ git_writestream **out,
+ git_repository *repo,
+ const char *hintpath);
+GIT_EXTERN(int) git_blob_create_fromstream_commit(
+ git_oid *out,
+ git_writestream *stream);
+GIT_EXTERN(int) git_blob_create_frombuffer(
+ git_oid *id, git_repository *repo, const void *buffer, size_t len);
+
+/** Deprecated in favor of `git_blob_filter`.
+ *
+ * @deprecated Use git_blob_filter
+ * @see git_blob_filter
+ */
+GIT_EXTERN(int) git_blob_filtered_content(
+ git_buf *out,
+ git_blob *blob,
+ const char *as_path,
+ int check_for_binary_data);
+
+/**@}*/
+
/** @name Deprecated Buffer Functions
*
* These functions and enumeration values are retained for backward
/**@}*/
+/** @name Deprecated Config Functions and Constants
+ */
+/**@{*/
+
+#define GIT_CVAR_FALSE GIT_CONFIGMAP_FALSE
+#define GIT_CVAR_TRUE GIT_CONFIGMAP_TRUE
+#define GIT_CVAR_INT32 GIT_CONFIGMAP_INT32
+#define GIT_CVAR_STRING GIT_CONFIGMAP_STRING
+
+typedef git_configmap git_cvar_map;
+
+/**@}*/
+
/** @name Deprecated Error Functions and Constants
*
* These functions and enumeration values are retained for backward
GIT_EXTERN(void) giterr_set_str(int error_class, const char *string);
/**
- * Indicates that an out-of-memory situation occured. This is an alias
+ * Indicates that an out-of-memory situation occurred. This is an alias
* of `git_error_set_oom` and is preserved for backward compatibility.
*
* This function is deprecated, but there is no plan to remove this
/**@}*/
-/** @name Deprecated Index Constants
+/** @name Deprecated Index Functions and Constants
*
- * These enumeration values are retained for backward compatibility.
- * The newer versions of these values should be preferred in all new code.
+ * These functions and enumeration values are retained for backward
+ * compatibility. The newer versions of these values should be
+ * preferred in all new code.
*
* There is no plan to remove these backward compatibility values at
* this time.
#define GIT_INDEXCAP_NO_SYMLINKS GIT_INDEX_CAPABILITY_NO_SYMLINKS
#define GIT_INDEXCAP_FROM_OWNER GIT_INDEX_CAPABILITY_FROM_OWNER
+GIT_EXTERN(int) git_index_add_frombuffer(
+ git_index *index,
+ const git_index_entry *entry,
+ const void *buffer, size_t len);
+
/**@}*/
/** @name Deprecated Object Constants
#define GIT_OBJ_OFS_DELTA GIT_OBJECT_OFS_DELTA
#define GIT_OBJ_REF_DELTA GIT_OBJECT_REF_DELTA
+/**
+ * Get the size in bytes for the structure which
+ * acts as an in-memory representation of any given
+ * object type.
+ *
+ * For all the core types, this would the equivalent
+ * of calling `sizeof(git_commit)` if the core types
+ * were not opaque on the external API.
+ *
+ * @param type object type to get its size
+ * @return size in bytes of the object
+ */
+GIT_EXTERN(size_t) git_object__size(git_object_t type);
+
/**@}*/
/** @name Deprecated Reference Constants
#define GIT_REF_FORMAT_REFSPEC_PATTERN GIT_REFERENCE_FORMAT_REFSPEC_PATTERN
#define GIT_REF_FORMAT_REFSPEC_SHORTHAND GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND
+GIT_EXTERN(int) git_tag_create_frombuffer(
+ git_oid *oid,
+ git_repository *repo,
+ const char *buffer,
+ int force);
+
+/**@}*/
+
+/** @name Deprecated Credential Types
+ *
+ * These types are retained for backward compatibility. The newer
+ * versions of these values should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+
+typedef git_credential git_cred;
+typedef git_credential_userpass_plaintext git_cred_userpass_plaintext;
+typedef git_credential_username git_cred_username;
+typedef git_credential_default git_cred_default;
+typedef git_credential_ssh_key git_cred_ssh_key;
+typedef git_credential_ssh_interactive git_cred_ssh_interactive;
+typedef git_credential_ssh_custom git_cred_ssh_custom;
+
+typedef git_credential_acquire_cb git_cred_acquire_cb;
+typedef git_credential_sign_cb git_cred_sign_callback;
+typedef git_credential_sign_cb git_cred_sign_cb;
+typedef git_credential_ssh_interactive_cb git_cred_ssh_interactive_callback;
+typedef git_credential_ssh_interactive_cb git_cred_ssh_interactive_cb;
+
+#define git_credtype_t git_credential_t
+
+#define GIT_CREDTYPE_USERPASS_PLAINTEXT GIT_CREDENTIAL_USERPASS_PLAINTEXT
+#define GIT_CREDTYPE_SSH_KEY GIT_CREDENTIAL_SSH_KEY
+#define GIT_CREDTYPE_SSH_CUSTOM GIT_CREDENTIAL_SSH_CUSTOM
+#define GIT_CREDTYPE_DEFAULT GIT_CREDENTIAL_DEFAULT
+#define GIT_CREDTYPE_SSH_INTERACTIVE GIT_CREDENTIAL_SSH_INTERACTIVE
+#define GIT_CREDTYPE_USERNAME GIT_CREDENTIAL_USERNAME
+#define GIT_CREDTYPE_SSH_MEMORY GIT_CREDENTIAL_SSH_MEMORY
+
+GIT_EXTERN(void) git_cred_free(git_credential *cred);
+GIT_EXTERN(int) git_cred_has_username(git_credential *cred);
+GIT_EXTERN(const char *) git_cred_get_username(git_credential *cred);
+GIT_EXTERN(int) git_cred_userpass_plaintext_new(
+ git_credential **out,
+ const char *username,
+ const char *password);
+GIT_EXTERN(int) git_cred_default_new(git_credential **out);
+GIT_EXTERN(int) git_cred_username_new(git_credential **out, const char *username);
+GIT_EXTERN(int) git_cred_ssh_key_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase);
+GIT_EXTERN(int) git_cred_ssh_key_memory_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase);
+GIT_EXTERN(int) git_cred_ssh_interactive_new(
+ git_credential **out,
+ const char *username,
+ git_credential_ssh_interactive_cb prompt_callback,
+ void *payload);
+GIT_EXTERN(int) git_cred_ssh_key_from_agent(
+ git_credential **out,
+ const char *username);
+GIT_EXTERN(int) git_cred_ssh_custom_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ size_t publickey_len,
+ git_credential_sign_cb sign_callback,
+ void *payload);
+
+/* Deprecated Credential Helper Types */
+
+typedef git_credential_userpass_payload git_cred_userpass_payload;
+
+GIT_EXTERN(int) git_cred_userpass(
+ git_credential **out,
+ const char *url,
+ const char *user_from_url,
+ unsigned int allowed_types,
+ void *payload);
+
+/**@}*/
+
+/** @name Deprecated Trace Callback Types
+ *
+ * These types are retained for backward compatibility. The newer
+ * versions of these values should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+typedef git_trace_cb git_trace_callback;
+
+/**@}*/
+
+/** @name Deprecated Object ID Types
+ *
+ * These types are retained for backward compatibility. The newer
+ * versions of these values should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+GIT_EXTERN(int) git_oid_iszero(const git_oid *id);
+
+/**@}*/
+
+/** @name Deprecated Transfer Progress Types
+ *
+ * These types are retained for backward compatibility. The newer
+ * versions of these values should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+/**
+ * This structure is used to provide callers information about the
+ * progress of indexing a packfile.
+ *
+ * This type is deprecated, but there is no plan to remove this
+ * type definition at this time.
+ */
+typedef git_indexer_progress git_transfer_progress;
+
+/**
+ * Type definition for progress callbacks during indexing.
+ *
+ * This type is deprecated, but there is no plan to remove this
+ * type definition at this time.
+ */
+typedef git_indexer_progress_cb git_transfer_progress_cb;
+
+/**
+ * Type definition for push transfer progress callbacks.
+ *
+ * This type is deprecated, but there is no plan to remove this
+ * type definition at this time.
+ */
+typedef git_push_transfer_progress_cb git_push_transfer_progress;
+
+ /** The type of a remote completion event */
+#define git_remote_completion_type git_remote_completion_t
+
+/**
+ * Callback for listing the remote heads
+ */
+typedef int GIT_CALLBACK(git_headlist_cb)(git_remote_head *rhead, void *payload);
+
+/**@}*/
+
+/** @name Deprecated String Array Functions
+ *
+ * These types are retained for backward compatibility. The newer
+ * versions of these values should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility values at
+ * this time.
+ */
+/**@{*/
+
+/**
+ * Copy a string array object from source to target.
+ *
+ * This function is deprecated, but there is no plan to remove this
+ * function at this time.
+ *
+ * @param tgt target
+ * @param src source
+ * @return 0 on success, < 0 on allocation failure
+ */
+GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src);
+
+/**
+ * Free the memory referred to by the git_strarray. This is an alias of
+ * `git_strarray_dispose` and is preserved for backward compatibility.
+ *
+ * This function is deprecated, but there is no plan to remove this
+ * function at this time.
+ *
+ * @deprecated Use git_strarray_dispose
+ * @see git_strarray_dispose
+ */
+GIT_EXTERN(void) git_strarray_free(git_strarray *array);
+
+/**@}*/
+
+/** @name Deprecated Options Initialization Functions
+ *
+ * These functions are retained for backward compatibility. The newer
+ * versions of these functions should be preferred in all new code.
+ *
+ * There is no plan to remove these backward compatibility functions at
+ * this time.
+ */
+/**@{*/
+
+GIT_EXTERN(int) git_blame_init_options(git_blame_options *opts, unsigned int version);
+GIT_EXTERN(int) git_checkout_init_options(git_checkout_options *opts, unsigned int version);
+GIT_EXTERN(int) git_cherrypick_init_options(git_cherrypick_options *opts, unsigned int version);
+GIT_EXTERN(int) git_clone_init_options(git_clone_options *opts, unsigned int version);
+GIT_EXTERN(int) git_describe_init_options(git_describe_options *opts, unsigned int version);
+GIT_EXTERN(int) git_describe_init_format_options(git_describe_format_options *opts, unsigned int version);
+GIT_EXTERN(int) git_diff_init_options(git_diff_options *opts, unsigned int version);
+GIT_EXTERN(int) git_diff_find_init_options(git_diff_find_options *opts, unsigned int version);
+GIT_EXTERN(int) git_diff_format_email_init_options(git_diff_format_email_options *opts, unsigned int version);
+GIT_EXTERN(int) git_diff_patchid_init_options(git_diff_patchid_options *opts, unsigned int version);
+GIT_EXTERN(int) git_fetch_init_options(git_fetch_options *opts, unsigned int version);
+GIT_EXTERN(int) git_indexer_init_options(git_indexer_options *opts, unsigned int version);
+GIT_EXTERN(int) git_merge_init_options(git_merge_options *opts, unsigned int version);
+GIT_EXTERN(int) git_merge_file_init_input(git_merge_file_input *input, unsigned int version);
+GIT_EXTERN(int) git_merge_file_init_options(git_merge_file_options *opts, unsigned int version);
+GIT_EXTERN(int) git_proxy_init_options(git_proxy_options *opts, unsigned int version);
+GIT_EXTERN(int) git_push_init_options(git_push_options *opts, unsigned int version);
+GIT_EXTERN(int) git_rebase_init_options(git_rebase_options *opts, unsigned int version);
+GIT_EXTERN(int) git_remote_create_init_options(git_remote_create_options *opts, unsigned int version);
+GIT_EXTERN(int) git_repository_init_init_options(git_repository_init_options *opts, unsigned int version);
+GIT_EXTERN(int) git_revert_init_options(git_revert_options *opts, unsigned int version);
+GIT_EXTERN(int) git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version);
+GIT_EXTERN(int) git_status_init_options(git_status_options *opts, unsigned int version);
+GIT_EXTERN(int) git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version);
+GIT_EXTERN(int) git_worktree_add_init_options(git_worktree_add_options *opts, unsigned int version);
+GIT_EXTERN(int) git_worktree_prune_init_options(git_worktree_prune_options *opts, unsigned int version);
+
/**@}*/
/** @} */
* Describe options structure
*
* Initialize with `GIT_DESCRIBE_OPTIONS_INIT`. Alternatively, you can
- * use `git_describe_init_options`.
+ * use `git_describe_options_init`.
*
*/
typedef struct git_describe_options {
* @param version The struct version; pass `GIT_DESCRIBE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_describe_init_options(git_describe_options *opts, unsigned int version);
+GIT_EXTERN(int) git_describe_options_init(git_describe_options *opts, unsigned int version);
/**
* Describe format options structure
*
* Initialize with `GIT_DESCRIBE_FORMAT_OPTIONS_INIT`. Alternatively, you can
- * use `git_describe_format_init_options`.
+ * use `git_describe_format_options_init`.
*
*/
typedef struct {
* @param version The struct version; pass `GIT_DESCRIBE_FORMAT_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_describe_init_format_options(git_describe_format_options *opts, unsigned int version);
+GIT_EXTERN(int) git_describe_format_options_init(git_describe_format_options *opts, unsigned int version);
/**
* A struct that stores the result of a describe operation.
/** Include unreadable files in the diff */
GIT_DIFF_INCLUDE_UNREADABLE = (1u << 16),
-
+
/** Include unreadable files in the diff */
GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED = (1u << 17),
* abbreviated to something reasonable, like 7 characters.
*/
typedef struct {
- git_oid id;
- const char *path;
- git_off_t size;
- uint32_t flags;
- uint16_t mode;
- uint16_t id_abbrev;
+ git_oid id;
+ const char *path;
+ git_object_size_t size;
+ uint32_t flags;
+ uint16_t mode;
+ uint16_t id_abbrev;
} git_diff_file;
/**
* @param version The struct version; pass `GIT_DIFF_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_diff_init_options(
+GIT_EXTERN(int) git_diff_options_init(
git_diff_options *opts,
unsigned int version);
* @param version The struct version; pass `GIT_DIFF_FIND_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_diff_find_init_options(
+GIT_EXTERN(int) git_diff_find_options_init(
git_diff_find_options *opts,
unsigned int version);
GIT_DIFF_FORMAT_RAW = 3u, /**< like git diff --raw */
GIT_DIFF_FORMAT_NAME_ONLY = 4u, /**< like git diff --name-only */
GIT_DIFF_FORMAT_NAME_STATUS = 5u, /**< like git diff --name-status */
+ GIT_DIFF_FORMAT_PATCH_ID = 6u, /**< git diff as used by git patch-id */
} git_diff_format_t;
/**
typedef struct {
unsigned int version;
- git_diff_format_email_flags_t flags;
+ /** see `git_diff_format_email_flags_t` above */
+ uint32_t flags;
/** This patch number */
size_t patch_no;
git_commit *commit,
size_t patch_no,
size_t total_patches,
- git_diff_format_email_flags_t flags,
+ uint32_t flags,
const git_diff_options *diff_opts);
/**
* @param version The struct version; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_diff_format_email_init_options(
+GIT_EXTERN(int) git_diff_format_email_options_init(
git_diff_format_email_options *opts,
unsigned int version);
* Patch ID options structure
*
* Initialize with `GIT_PATCHID_OPTIONS_INIT`. Alternatively, you can
- * use `git_patchid_init_options`.
+ * use `git_diff_patchid_options_init`.
*
*/
typedef struct git_diff_patchid_options {
* @param version The struct version; pass `GIT_DIFF_PATCHID_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_diff_patchid_init_options(
+GIT_EXTERN(int) git_diff_patchid_options_init(
git_diff_patchid_options *opts,
unsigned int version);
GIT_ERROR_FILESYSTEM,
GIT_ERROR_PATCH,
GIT_ERROR_WORKTREE,
- GIT_ERROR_SHA1
+ GIT_ERROR_SHA1,
+ GIT_ERROR_HTTP,
+ GIT_ERROR_INTERNAL
} git_error_t;
/**
* @param error_class One of the `git_error_t` enum above describing the
* general subsystem that is responsible for the error.
* @param string The formatted error message to keep
+ * @return 0 on success or -1 on failure
*/
-GIT_EXTERN(void) git_error_set_str(int error_class, const char *string);
+GIT_EXTERN(int) git_error_set_str(int error_class, const char *string);
/**
* Set the error message to a special value for memory allocation failure.
*/
typedef enum {
GIT_FILTER_DEFAULT = 0u,
+
+ /** Don't error for `safecrlf` violations, allow them to continue. */
GIT_FILTER_ALLOW_UNSAFE = (1u << 0),
+
+ /** Don't load `/etc/gitattributes` (or the system equivalent) */
+ GIT_FILTER_NO_SYSTEM_ATTRIBUTES = (1u << 1),
+
+ /** Load attributes from `.gitattributes` in the root of HEAD */
+ GIT_FILTER_ATTRIBUTES_FROM_HEAD = (1u << 2),
} git_filter_flag_t;
/**
GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2),
} git_index_add_option_t;
+/** Git index stage states */
typedef enum {
/**
* Match any index stage.
*
* If a previous index entry exists that has the same path as the
* given 'entry', it will be replaced. Otherwise, the 'entry' will be
- * added. The `id` and the `file_size` of the 'entry' are updated with the
- * real value of the blob.
+ * added.
*
* This forces the file to be added to the index, not looking
* at gitignore rules. Those rules can be evaluated through
* @param len length of the data
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_index_add_frombuffer(
+GIT_EXTERN(int) git_index_add_from_buffer(
git_index *index,
const git_index_entry *entry,
const void *buffer, size_t len);
GIT_BEGIN_DECL
+/** A git indexer object */
typedef struct git_indexer git_indexer;
+/**
+ * This structure is used to provide callers information about the
+ * progress of indexing a packfile, either directly or part of a
+ * fetch or clone that downloads a packfile.
+ */
+typedef struct git_indexer_progress {
+ /** number of objects in the packfile being indexed */
+ unsigned int total_objects;
+
+ /** received objects that have been hashed */
+ unsigned int indexed_objects;
+
+ /** received_objects: objects which have been downloaded */
+ unsigned int received_objects;
+
+ /**
+ * locally-available objects that have been injected in order
+ * to fix a thin pack
+ */
+ unsigned int local_objects;
+
+ /** number of deltas in the packfile being indexed */
+ unsigned int total_deltas;
+
+ /** received deltas that have been indexed */
+ unsigned int indexed_deltas;
+
+ /** size of the packfile received up to now */
+ size_t received_bytes;
+} git_indexer_progress;
+
+/**
+ * Type for progress callbacks during indexing. Return a value less
+ * than zero to cancel the indexing or download.
+ *
+ * @param stats Structure containing information about the state of the tran sfer
+ * @param payload Payload provided by caller
+ */
+typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *stats, void *payload);
+
+/**
+ * Options for indexer configuration
+ */
typedef struct git_indexer_options {
unsigned int version;
/** progress_cb function to call with progress information */
- git_transfer_progress_cb progress_cb;
+ git_indexer_progress_cb progress_cb;
/** progress_cb_payload payload for the progress callback */
void *progress_cb_payload;
* @param version Version of struct; pass `GIT_INDEXER_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_indexer_init_options(
+GIT_EXTERN(int) git_indexer_options_init(
git_indexer_options *opts,
unsigned int version);
* @param size the size of the data in bytes
* @param stats stat storage
*/
-GIT_EXTERN(int) git_indexer_append(git_indexer *idx, const void *data, size_t size, git_transfer_progress *stats);
+GIT_EXTERN(int) git_indexer_append(git_indexer *idx, const void *data, size_t size, git_indexer_progress *stats);
/**
* Finalize the pack and index
*
* @param idx the indexer
*/
-GIT_EXTERN(int) git_indexer_commit(git_indexer *idx, git_transfer_progress *stats);
+GIT_EXTERN(int) git_indexer_commit(git_indexer *idx, git_indexer_progress *stats);
/**
* Get the packfile's hash
+++ /dev/null
-// ISO C9x compliant inttypes.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
-//
-// Copyright (c) 2006 Alexander Chemeris
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. 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.
-//
-// 3. The name of the author may be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_INTTYPES_H_ // [
-#define _MSC_INTTYPES_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#if _MSC_VER >= 1600
-#include <stdint.h>
-#else
-#include "stdint.h"
-#endif
-
-// 7.8 Format conversion of integer types
-
-typedef struct {
- intmax_t quot;
- intmax_t rem;
-} imaxdiv_t;
-
-// 7.8.1 Macros for format specifiers
-
-#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
-
-// The fprintf macros for signed integers are:
-#define PRId8 "d"
-#define PRIi8 "i"
-#define PRIdLEAST8 "d"
-#define PRIiLEAST8 "i"
-#define PRIdFAST8 "d"
-#define PRIiFAST8 "i"
-
-#define PRId16 "hd"
-#define PRIi16 "hi"
-#define PRIdLEAST16 "hd"
-#define PRIiLEAST16 "hi"
-#define PRIdFAST16 "hd"
-#define PRIiFAST16 "hi"
-
-#define PRId32 "I32d"
-#define PRIi32 "I32i"
-#define PRIdLEAST32 "I32d"
-#define PRIiLEAST32 "I32i"
-#define PRIdFAST32 "I32d"
-#define PRIiFAST32 "I32i"
-
-#define PRId64 "I64d"
-#define PRIi64 "I64i"
-#define PRIdLEAST64 "I64d"
-#define PRIiLEAST64 "I64i"
-#define PRIdFAST64 "I64d"
-#define PRIiFAST64 "I64i"
-
-#define PRIdMAX "I64d"
-#define PRIiMAX "I64i"
-
-#define PRIdPTR "Id"
-#define PRIiPTR "Ii"
-
-// The fprintf macros for unsigned integers are:
-#define PRIo8 "o"
-#define PRIu8 "u"
-#define PRIx8 "x"
-#define PRIX8 "X"
-#define PRIoLEAST8 "o"
-#define PRIuLEAST8 "u"
-#define PRIxLEAST8 "x"
-#define PRIXLEAST8 "X"
-#define PRIoFAST8 "o"
-#define PRIuFAST8 "u"
-#define PRIxFAST8 "x"
-#define PRIXFAST8 "X"
-
-#define PRIo16 "ho"
-#define PRIu16 "hu"
-#define PRIx16 "hx"
-#define PRIX16 "hX"
-#define PRIoLEAST16 "ho"
-#define PRIuLEAST16 "hu"
-#define PRIxLEAST16 "hx"
-#define PRIXLEAST16 "hX"
-#define PRIoFAST16 "ho"
-#define PRIuFAST16 "hu"
-#define PRIxFAST16 "hx"
-#define PRIXFAST16 "hX"
-
-#define PRIo32 "I32o"
-#define PRIu32 "I32u"
-#define PRIx32 "I32x"
-#define PRIX32 "I32X"
-#define PRIoLEAST32 "I32o"
-#define PRIuLEAST32 "I32u"
-#define PRIxLEAST32 "I32x"
-#define PRIXLEAST32 "I32X"
-#define PRIoFAST32 "I32o"
-#define PRIuFAST32 "I32u"
-#define PRIxFAST32 "I32x"
-#define PRIXFAST32 "I32X"
-
-#define PRIo64 "I64o"
-#define PRIu64 "I64u"
-#define PRIx64 "I64x"
-#define PRIX64 "I64X"
-#define PRIoLEAST64 "I64o"
-#define PRIuLEAST64 "I64u"
-#define PRIxLEAST64 "I64x"
-#define PRIXLEAST64 "I64X"
-#define PRIoFAST64 "I64o"
-#define PRIuFAST64 "I64u"
-#define PRIxFAST64 "I64x"
-#define PRIXFAST64 "I64X"
-
-#define PRIoMAX "I64o"
-#define PRIuMAX "I64u"
-#define PRIxMAX "I64x"
-#define PRIXMAX "I64X"
-
-#define PRIoPTR "Io"
-#define PRIuPTR "Iu"
-#define PRIxPTR "Ix"
-#define PRIXPTR "IX"
-
-// The fscanf macros for signed integers are:
-#define SCNd8 "d"
-#define SCNi8 "i"
-#define SCNdLEAST8 "d"
-#define SCNiLEAST8 "i"
-#define SCNdFAST8 "d"
-#define SCNiFAST8 "i"
-
-#define SCNd16 "hd"
-#define SCNi16 "hi"
-#define SCNdLEAST16 "hd"
-#define SCNiLEAST16 "hi"
-#define SCNdFAST16 "hd"
-#define SCNiFAST16 "hi"
-
-#define SCNd32 "ld"
-#define SCNi32 "li"
-#define SCNdLEAST32 "ld"
-#define SCNiLEAST32 "li"
-#define SCNdFAST32 "ld"
-#define SCNiFAST32 "li"
-
-#define SCNd64 "I64d"
-#define SCNi64 "I64i"
-#define SCNdLEAST64 "I64d"
-#define SCNiLEAST64 "I64i"
-#define SCNdFAST64 "I64d"
-#define SCNiFAST64 "I64i"
-
-#define SCNdMAX "I64d"
-#define SCNiMAX "I64i"
-
-#ifdef _WIN64 // [
-# define SCNdPTR "I64d"
-# define SCNiPTR "I64i"
-#else // _WIN64 ][
-# define SCNdPTR "ld"
-# define SCNiPTR "li"
-#endif // _WIN64 ]
-
-// The fscanf macros for unsigned integers are:
-#define SCNo8 "o"
-#define SCNu8 "u"
-#define SCNx8 "x"
-#define SCNX8 "X"
-#define SCNoLEAST8 "o"
-#define SCNuLEAST8 "u"
-#define SCNxLEAST8 "x"
-#define SCNXLEAST8 "X"
-#define SCNoFAST8 "o"
-#define SCNuFAST8 "u"
-#define SCNxFAST8 "x"
-#define SCNXFAST8 "X"
-
-#define SCNo16 "ho"
-#define SCNu16 "hu"
-#define SCNx16 "hx"
-#define SCNX16 "hX"
-#define SCNoLEAST16 "ho"
-#define SCNuLEAST16 "hu"
-#define SCNxLEAST16 "hx"
-#define SCNXLEAST16 "hX"
-#define SCNoFAST16 "ho"
-#define SCNuFAST16 "hu"
-#define SCNxFAST16 "hx"
-#define SCNXFAST16 "hX"
-
-#define SCNo32 "lo"
-#define SCNu32 "lu"
-#define SCNx32 "lx"
-#define SCNX32 "lX"
-#define SCNoLEAST32 "lo"
-#define SCNuLEAST32 "lu"
-#define SCNxLEAST32 "lx"
-#define SCNXLEAST32 "lX"
-#define SCNoFAST32 "lo"
-#define SCNuFAST32 "lu"
-#define SCNxFAST32 "lx"
-#define SCNXFAST32 "lX"
-
-#define SCNo64 "I64o"
-#define SCNu64 "I64u"
-#define SCNx64 "I64x"
-#define SCNX64 "I64X"
-#define SCNoLEAST64 "I64o"
-#define SCNuLEAST64 "I64u"
-#define SCNxLEAST64 "I64x"
-#define SCNXLEAST64 "I64X"
-#define SCNoFAST64 "I64o"
-#define SCNuFAST64 "I64u"
-#define SCNxFAST64 "I64x"
-#define SCNXFAST64 "I64X"
-
-#define SCNoMAX "I64o"
-#define SCNuMAX "I64u"
-#define SCNxMAX "I64x"
-#define SCNXMAX "I64X"
-
-#ifdef _WIN64 // [
-# define SCNoPTR "I64o"
-# define SCNuPTR "I64u"
-# define SCNxPTR "I64x"
-# define SCNXPTR "I64X"
-#else // _WIN64 ][
-# define SCNoPTR "lo"
-# define SCNuPTR "lu"
-# define SCNxPTR "lx"
-# define SCNXPTR "lX"
-#endif // _WIN64 ]
-
-#endif // __STDC_FORMAT_MACROS ]
-
-// 7.8.2 Functions for greatest-width integer types
-
-// 7.8.2.1 The imaxabs function
-#define imaxabs _abs64
-
-// 7.8.2.2 The imaxdiv function
-
-// This is modified version of div() function from Microsoft's div.c found
-// in %MSVC.NET%\crt\src\div.c
-#ifdef STATIC_IMAXDIV // [
-static
-#else // STATIC_IMAXDIV ][
-_inline
-#endif // STATIC_IMAXDIV ]
-imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
-{
- imaxdiv_t result;
-
- result.quot = numer / denom;
- result.rem = numer % denom;
-
- if (numer < 0 && result.rem > 0) {
- // did division wrong; must fix up
- ++result.quot;
- result.rem -= denom;
- }
-
- return result;
-}
-
-// 7.8.2.3 The strtoimax and strtoumax functions
-#define strtoimax _strtoi64
-#define strtoumax _strtoui64
-
-// 7.8.2.4 The wcstoimax and wcstoumax functions
-#define wcstoimax _wcstoi64
-#define wcstoumax _wcstoui64
-
-
-#endif // _MSC_INTTYPES_H_ ]
* `GIT_MERGE_FILE_INPUT_VERSION` here.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_merge_file_init_input(
+GIT_EXTERN(int) git_merge_file_input_init(
git_merge_file_input *opts,
unsigned int version);
git_merge_file_favor_t favor;
/** see `git_merge_file_flag_t` above */
- git_merge_file_flag_t flags;
+ uint32_t flags;
/** The size of conflict markers (eg, "<<<<<<<"). Default is
* GIT_MERGE_CONFLICT_MARKER_SIZE. */
* @param version The struct version; pass `GIT_MERGE_FILE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_merge_file_init_options(
- git_merge_file_options *opts,
- unsigned int version);
+GIT_EXTERN(int) git_merge_file_options_init(git_merge_file_options *opts, unsigned int version);
/**
* Information about file-level merging
unsigned int version;
/** See `git_merge_flag_t` above */
- git_merge_flag_t flags;
+ uint32_t flags;
/**
* Similarity to consider a file renamed (default 50). If
git_merge_file_favor_t file_favor;
/** see `git_merge_file_flag_t` above */
- git_merge_file_flag_t file_flags;
+ uint32_t file_flags;
} git_merge_options;
#define GIT_MERGE_OPTIONS_VERSION 1
* @param version The struct version; pass `GIT_MERGE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_merge_init_options(
- git_merge_options *opts,
- unsigned int version);
+GIT_EXTERN(int) git_merge_options_init(git_merge_options *opts, unsigned int version);
/**
* The results of `git_merge_analysis` indicate the merge opportunities.
char *symref_target;
};
-/**
- * Callback for listing the remote heads
- */
-typedef int GIT_CALLBACK(git_headlist_cb)(git_remote_head *rhead, void *payload);
-
/** @} */
GIT_END_DECL
#endif
*/
GIT_BEGIN_DECL
+#define GIT_OBJECT_SIZE_MAX UINT64_MAX
+
/**
* Lookup a reference to one of the objects in a repository.
*
*/
GIT_EXTERN(int) git_object_typeisloose(git_object_t type);
-/**
- * Get the size in bytes for the structure which
- * acts as an in-memory representation of any given
- * object type.
- *
- * For all the core types, this would the equivalent
- * of calling `sizeof(git_commit)` if the core types
- * were not opaque on the external API.
- *
- * @param type object type to get its size
- * @return size in bytes of the object
- */
-GIT_EXTERN(size_t) git_object__size(git_object_t type);
-
/**
* Recursively peel an object until an object of the specified type is met.
*
#include "types.h"
#include "oid.h"
#include "oidarray.h"
+#include "indexer.h"
/**
* @file git2/odb.h
* @param type type of the object that will be written
* @return 0 if the stream was created; error code otherwise
*/
-GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **out, git_odb *db, git_off_t size, git_object_t type);
+GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **out, git_odb *db, git_object_size_t size, git_object_t type);
/**
* Write to an odb stream
GIT_EXTERN(int) git_odb_write_pack(
git_odb_writepack **out,
git_odb *db,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress_cb progress_cb,
void *progress_payload);
/**
#include "common.h"
#include "types.h"
+#include "indexer.h"
/**
* @file git2/backend.h
unsigned int mode;
void *hash_ctx;
- git_off_t declared_size;
- git_off_t received_bytes;
+ git_object_size_t declared_size;
+ git_object_size_t received_bytes;
/**
* Write at most `len` bytes into `buffer` and advance the stream.
struct git_odb_writepack {
git_odb_backend *backend;
- int GIT_CALLBACK(append)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats);
- int GIT_CALLBACK(commit)(git_odb_writepack *writepack, git_transfer_progress *stats);
+ int GIT_CALLBACK(append)(git_odb_writepack *writepack, const void *data, size_t size, git_indexer_progress *stats);
+ int GIT_CALLBACK(commit)(git_odb_writepack *writepack, git_indexer_progress *stats);
void GIT_CALLBACK(free)(git_odb_writepack *writepack);
};
*
* @param out oid structure the result is written into.
* @param raw the raw input bytes to be copied.
+ * @return 0 on success or error code
*/
-GIT_EXTERN(void) git_oid_fromraw(git_oid *out, const unsigned char *raw);
+GIT_EXTERN(int) git_oid_fromraw(git_oid *out, const unsigned char *raw);
/**
* Format a git_oid into a hex string.
* oid digits are written; a '\\0' terminator must be added
* by the caller if it is required.
* @param id oid structure to format.
+ * @return 0 on success or error code
*/
-GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id);
+GIT_EXTERN(int) git_oid_fmt(char *out, const git_oid *id);
/**
* Format a git_oid into a partial hex string.
* will be zeroed; if not, a '\0' terminator is NOT added.
* @param n number of characters to write into out string
* @param id oid structure to format.
+ * @return 0 on success or error code
*/
-GIT_EXTERN(void) git_oid_nfmt(char *out, size_t n, const git_oid *id);
+GIT_EXTERN(int) git_oid_nfmt(char *out, size_t n, const git_oid *id);
/**
* Format a git_oid into a loose-object path string.
* oid digits are written; a '\\0' terminator must be added
* by the caller if it is required.
* @param id oid structure to format.
+ * @return 0 on success, non-zero callback return value, or error code
*/
-GIT_EXTERN(void) git_oid_pathfmt(char *out, const git_oid *id);
+GIT_EXTERN(int) git_oid_pathfmt(char *out, const git_oid *id);
/**
* Format a git_oid into a statically allocated c-string.
*
* @param out oid structure the result is written into.
* @param src oid structure to copy from.
+ * @return 0 on success or error code
*/
-GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src);
+GIT_EXTERN(int) git_oid_cpy(git_oid *out, const git_oid *src);
/**
* Compare two oid structures.
*
* @return 1 if all zeros, 0 otherwise.
*/
-GIT_EXTERN(int) git_oid_iszero(const git_oid *id);
+GIT_EXTERN(int) git_oid_is_zero(const git_oid *id);
/**
* OID Shortener object
#include "common.h"
#include "oid.h"
+#include "indexer.h"
/**
* @file git2/pack.h
* Write the new pack and corresponding index file to path.
*
* @param pb The packbuilder
- * @param path to the directory where the packfile and index should be stored
+ * @param path Path to the directory where the packfile and index should be stored, or NULL for default location
* @param mode permissions to use creating a packfile or 0 for defaults
* @param progress_cb function to call with progress information from the indexer (optional)
* @param progress_cb_payload payload for the progress callback (optional)
git_packbuilder *pb,
const char *path,
unsigned int mode,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress_cb progress_cb,
void *progress_cb_payload);
/**
*/
GIT_EXTERN(const git_oid *) git_packbuilder_hash(git_packbuilder *pb);
+/**
+ * Callback used to iterate over packed objects
+ *
+ * @see git_packbuilder_foreach
+ *
+ * @param buf A pointer to the object's data
+ * @param size The size of the underlying object
+ * @param payload Payload passed to git_packbuilder_foreach
+ * @return non-zero to terminate the iteration
+ */
typedef int GIT_CALLBACK(git_packbuilder_foreach_cb)(void *buf, size_t size, void *payload);
/**
#define INCLUDE_git_proxy_h__
#include "common.h"
-#include "transport.h"
+
+#include "cert.h"
+#include "credential.h"
GIT_BEGIN_DECL
* Returning GIT_PASSTHROUGH will make libgit2 behave as
* though this field isn't set.
*/
- git_cred_acquire_cb credentials;
+ git_credential_acquire_cb credentials;
/**
* If cert verification fails, this will be called to let the
* connection to proceed. Returns 0 to allow the connection
* or a negative value to indicate an error.
*/
- git_transport_certificate_check_cb certificate_check;
+ git_transport_certificate_check_cb certificate_check;
/**
* Payload to be provided to the credentials and certificate
* @param version The struct version; pass `GIT_PROXY_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_proxy_init_options(git_proxy_options *opts, unsigned int version);
+GIT_EXTERN(int) git_proxy_options_init(git_proxy_options *opts, unsigned int version);
GIT_END_DECL
#include "annotated_commit.h"
#include "merge.h"
#include "checkout.h"
+#include "commit.h"
/**
* @file git2/rebase.h
* `abort` to match git semantics.
*/
git_checkout_options checkout_options;
+
+ /**
+ * If provided, this will be called with the commit content, allowing
+ * a signature to be added to the rebase commit. Can be skipped with
+ * GIT_PASSTHROUGH. If GIT_PASSTHROUGH is returned, a commit will be made
+ * without a signature.
+ * This field is only used when performing git_rebase_commit.
+ */
+ git_commit_signing_cb signing_cb;
+
+ /**
+ * This will be passed to each of the callbacks in this struct
+ * as the last parameter.
+ */
+ void *payload;
} git_rebase_options;
/**
#define GIT_REBASE_OPTIONS_VERSION 1
#define GIT_REBASE_OPTIONS_INIT \
{ GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \
- GIT_CHECKOUT_OPTIONS_INIT}
+ GIT_CHECKOUT_OPTIONS_INIT, NULL, NULL }
/** Indicates that a rebase operation is not (yet) in progress. */
#define GIT_REBASE_NO_OPERATION SIZE_MAX
* @param version The struct version; pass `GIT_REBASE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_rebase_init_options(
+GIT_EXTERN(int) git_rebase_options_init(
git_rebase_options *opts,
unsigned int version);
git_repository *repo,
const git_rebase_options *opts);
+/**
+ * Gets the original `HEAD` ref name for merge rebases.
+ *
+ * @return The original `HEAD` ref name
+ */
+GIT_EXTERN(const char *) git_rebase_orig_head_name(git_rebase *rebase);
+
+/**
+ * Gets the original `HEAD` id for merge rebases.
+ *
+ * @return The original `HEAD` id
+ */
+GIT_EXTERN(const git_oid *) git_rebase_orig_head_id(git_rebase *rebase);
+
+/**
+ * Gets the `onto` ref name for merge rebases.
+ *
+ * @return The `onto` ref name
+ */
+GIT_EXTERN(const char *) git_rebase_onto_name(git_rebase *rebase);
+
+/**
+ * Gets the `onto` id for merge rebases.
+ *
+ * @return The `onto` id
+ */
+GIT_EXTERN(const git_oid *) git_rebase_onto_id(git_rebase *rebase);
+
/**
* Gets the count of rebase operations that are to be applied.
*
*/
GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo);
+/**
+ * Callback used to iterate over references
+ *
+ * @see git_reference_foreach
+ *
+ * @param reference The reference object
+ * @param payload Payload passed to git_reference_foreach
+ * @return non-zero to terminate the iteration
+ */
typedef int GIT_CALLBACK(git_reference_foreach_cb)(git_reference *reference, void *payload);
+
+/**
+ * Callback used to iterate over reference names
+ *
+ * @see git_reference_foreach_name
+ *
+ * @param name The reference name
+ * @param payload Payload passed to git_reference_foreach_name
+ * @return non-zero to terminate the iteration
+ */
typedef int GIT_CALLBACK(git_reference_foreach_name_cb)(const char *name, void *payload);
/**
* Remote creation options structure
*
* Initialize with `GIT_REMOTE_CREATE_OPTIONS_INIT`. Alternatively, you can
- * use `git_remote_create_init_options`.
+ * use `git_remote_create_options_init`.
*
*/
typedef struct git_remote_create_options {
* @param version The struct version; pass `GIT_REMOTE_CREATE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_remote_create_init_options(
+GIT_EXTERN(int) git_remote_create_options_init(
git_remote_create_options *opts,
unsigned int version);
* the operation has been cancelled and if so stops the operation.
*
* @param remote the remote
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_remote_stop(git_remote *remote);
+GIT_EXTERN(int) git_remote_stop(git_remote *remote);
/**
* Disconnect from the remote
* Close the connection to the remote.
*
* @param remote the remote to disconnect from
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_remote_disconnect(git_remote *remote);
+GIT_EXTERN(int) git_remote_disconnect(git_remote *remote);
/**
* Free the memory associated with a remote
* Argument to the completion callback which tells it which operation
* finished.
*/
-typedef enum git_remote_completion_type {
+typedef enum git_remote_completion_t {
GIT_REMOTE_COMPLETION_DOWNLOAD,
GIT_REMOTE_COMPLETION_INDEXING,
GIT_REMOTE_COMPLETION_ERROR,
-} git_remote_completion_type;
+} git_remote_completion_t;
/** Push network progress notification function */
-typedef int GIT_CALLBACK(git_push_transfer_progress)(
+typedef int GIT_CALLBACK(git_push_transfer_progress_cb)(
unsigned int current,
unsigned int total,
size_t bytes,
void* payload);
+
/**
* Represents an update which will be performed on the remote during push
*/
*/
typedef int GIT_CALLBACK(git_push_update_reference_cb)(const char *refname, const char *status, void *data);
+/**
+ * Callback to resolve URLs before connecting to remote
+ *
+ * If you return GIT_PASSTHROUGH, you don't need to write anything to
+ * url_resolved.
+ *
+ * @param url_resolved The buffer to write the resolved URL to
+ * @param url The URL to resolve
+ * @param direction GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
+ * @param payload Payload provided by the caller
+ * @return 0 on success, GIT_PASSTHROUGH or an error
+ */
+typedef int GIT_CALLBACK(git_url_resolve_cb)(git_buf *url_resolved, const char *url, int direction, void *payload);
+
/**
* The callback settings structure
*
* about the progress of the network operations.
*/
struct git_remote_callbacks {
- unsigned int version;
+ unsigned int version; /**< The version */
+
/**
* Textual progress from the remote. Text send over the
* progress side-band will be passed to this function (this is
* Completion is called when different parts of the download
* process are done (currently unused).
*/
- int GIT_CALLBACK(completion)(git_remote_completion_type type, void *data);
+ int GIT_CALLBACK(completion)(git_remote_completion_t type, void *data);
/**
* This will be called if the remote host requires
* Returning GIT_PASSTHROUGH will make libgit2 behave as
* though this field isn't set.
*/
- git_cred_acquire_cb credentials;
+ git_credential_acquire_cb credentials;
/**
* If cert verification fails, this will be called to let the
* called with the current count of progress done by the
* indexer.
*/
- git_transfer_progress_cb transfer_progress;
+ git_indexer_progress_cb transfer_progress;
/**
* Each time a reference is updated locally, this function
* inline with pack building operations, so performance may be
* affected.
*/
- git_push_transfer_progress push_transfer_progress;
+ git_push_transfer_progress_cb push_transfer_progress;
/**
* See documentation of git_push_update_reference_cb
* as the last parameter.
*/
void *payload;
+
+ /**
+ * Resolve URL before connecting to remote.
+ * The returned URL will be used to connect to the remote instead.
+ */
+ git_url_resolve_cb resolve_url;
};
#define GIT_REMOTE_CALLBACKS_VERSION 1
git_remote_callbacks *opts,
unsigned int version);
+/** Acceptable prune settings when fetching */
typedef enum {
/**
* Use the setting from the configuration
* @param version The struct version; pass `GIT_FETCH_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_fetch_init_options(
+GIT_EXTERN(int) git_fetch_options_init(
git_fetch_options *opts,
unsigned int version);
* @param version The struct version; pass `GIT_PUSH_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_push_init_options(
+GIT_EXTERN(int) git_push_options_init(
git_push_options *opts,
unsigned int version);
/**
* Get the statistics structure that is filled in by the fetch operation.
*/
-GIT_EXTERN(const git_transfer_progress *) git_remote_stats(git_remote *remote);
+GIT_EXTERN(const git_indexer_progress *) git_remote_stats(git_remote *remote);
/**
* Retrieve the tag auto-follow setting
* @param version The struct version; pass `GIT_REPOSITORY_INIT_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_repository_init_init_options(
+GIT_EXTERN(int) git_repository_init_options_init(
git_repository_init_options *opts,
unsigned int version);
GIT_REPOSITORY_ITEM_HOOKS,
GIT_REPOSITORY_ITEM_LOGS,
GIT_REPOSITORY_ITEM_MODULES,
- GIT_REPOSITORY_ITEM_WORKTREES
+ GIT_REPOSITORY_ITEM_WORKTREES,
+ GIT_REPOSITORY_ITEM__LAST
} git_repository_item_t;
/**
GIT_EXTERN(const char *) git_repository_workdir(const git_repository *repo);
/**
- * Get the path of the shared common directory for this repository
- *
- * If the repository is bare is not a worktree, the git directory
- * path is returned.
+ * Get the path of the shared common directory for this repository.
+ *
+ * If the repository is bare, it is the root directory for the repository.
+ * If the repository is a worktree, it is the parent repo's gitdir.
+ * Otherwise, it is the gitdir.
*
* @param repo A repository object
* @return the path to the common dir
*/
GIT_EXTERN(int) git_repository_state_cleanup(git_repository *repo);
+/**
+ * Callback used to iterate over each FETCH_HEAD entry
+ *
+ * @see git_repository_fetchhead_foreach
+ *
+ * @param ref_name The reference name
+ * @param remote_url The remote URL
+ * @param oid The reference target OID
+ * @param is_merge Was the reference the result of a merge
+ * @param payload Payload passed to git_repository_fetchhead_foreach
+ * @return non-zero to terminate the iteration
+ */
typedef int GIT_CALLBACK(git_repository_fetchhead_foreach_cb)(const char *ref_name,
const char *remote_url,
const git_oid *oid,
git_repository_fetchhead_foreach_cb callback,
void *payload);
+/**
+ * Callback used to iterate over each MERGE_HEAD entry
+ *
+ * @see git_repository_mergehead_foreach
+ *
+ * @param oid The merge OID
+ * @param payload Payload passed to git_repository_mergehead_foreach
+ * @return non-zero to terminate the iteration
+ */
typedef int GIT_CALLBACK(git_repository_mergehead_foreach_cb)(const git_oid *oid,
void *payload);
* @param version The struct version; pass `GIT_REVERT_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_revert_init_options(
+GIT_EXTERN(int) git_revert_options_init(
git_revert_options *opts,
unsigned int version);
* is over.
*
* @param walker handle to reset.
+ * @return 0 or an error code
*/
-GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
+GIT_EXTERN(int) git_revwalk_reset(git_revwalk *walker);
/**
* Add a new root for the traversal
*
* @param walk the walker being used for the traversal.
* @param sort_mode combination of GIT_SORT_XXX flags
+ * @return 0 or an error code
*/
-GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
+GIT_EXTERN(int) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
/**
* Push and hide the respective endpoints of the given range.
* Simplify the history by first-parent
*
* No parents other than the first for each commit will be enqueued.
+ *
+ * @return 0 or an error code
*/
-GIT_EXTERN(void) git_revwalk_simplify_first_parent(git_revwalk *walk);
+GIT_EXTERN(int) git_revwalk_simplify_first_parent(git_revwalk *walk);
/**
* Stash application options structure
*
* Initialize with `GIT_STASH_APPLY_OPTIONS_INIT`. Alternatively, you can
- * use `git_stash_apply_init_options`.
+ * use `git_stash_apply_options_init`.
*
*/
typedef struct git_stash_apply_options {
unsigned int version;
- /** See `git_stash_apply_flags_t`, above. */
- git_stash_apply_flags flags;
+ /** See `git_stash_apply_flags`, above. */
+ uint32_t flags;
/** Options to use when writing files to the working directory. */
git_checkout_options checkout_options;
* @param version The struct version; pass `GIT_STASH_APPLY_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_stash_apply_init_options(
+GIT_EXTERN(int) git_stash_apply_options_init(
git_stash_apply_options *opts, unsigned int version);
/**
/**
* Options to control how `git_status_foreach_ext()` will issue callbacks.
*
- * This structure is set so that zeroing it out will give you relatively
- * sane defaults.
+ * Initialize with `GIT_STATUS_OPTIONS_INIT`. Alternatively, you can
+ * use `git_status_options_init`.
*
- * The `show` value is one of the `git_status_show_t` constants that
- * control which files to scan and in what order.
- *
- * The `flags` value is an OR'ed combination of the `git_status_opt_t`
- * values above.
- *
- * The `pathspec` is an array of path patterns to match (using
- * fnmatch-style matching), or just an array of paths to match exactly if
- * `GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified in the flags.
- *
- * The `baseline` is the tree to be used for comparison to the working directory
- * and index; defaults to HEAD.
*/
typedef struct {
- unsigned int version;
+ unsigned int version; /**< The version */
+
+ /**
+ * The `show` value is one of the `git_status_show_t` constants that
+ * control which files to scan and in what order.
+ */
git_status_show_t show;
+
+ /**
+ * The `flags` value is an OR'ed combination of the `git_status_opt_t`
+ * values above.
+ */
unsigned int flags;
+
+ /**
+ * The `pathspec` is an array of path patterns to match (using
+ * fnmatch-style matching), or just an array of paths to match exactly if
+ * `GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified in the flags.
+ */
git_strarray pathspec;
+
+ /**
+ * The `baseline` is the tree to be used for comparison to the working directory
+ * and index; defaults to HEAD.
+ */
git_tree *baseline;
} git_status_options;
* @param version The struct version; pass `GIT_STATUS_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_status_init_options(
+GIT_EXTERN(int) git_status_options_init(
git_status_options *opts,
unsigned int version);
} git_strarray;
/**
- * Close a string array object
- *
- * This method should be called on `git_strarray` objects where the strings
- * array is allocated and contains allocated strings, such as what you
- * would get from `git_strarray_copy()`. Not doing so, will result in a
- * memory leak.
+ * Free the strings contained in a string array. This method should
+ * be called on `git_strarray` objects that were provided by the
+ * library. Not doing so, will result in a memory leak.
*
* This does not free the `git_strarray` itself, since the library will
- * never allocate that object directly itself (it is more commonly embedded
- * inside another struct or created on the stack).
+ * never allocate that object directly itself.
*
- * @param array git_strarray from which to free string data
+ * @param array The git_strarray that contains strings to free
*/
-GIT_EXTERN(void) git_strarray_free(git_strarray *array);
+GIT_EXTERN(void) git_strarray_dispose(git_strarray *array);
/**
* Copy a string array object from source to target.
* Submodule update options structure
*
* Initialize with `GIT_SUBMODULE_UPDATE_OPTIONS_INIT`. Alternatively, you can
- * use `git_submodule_update_init_options`.
+ * use `git_submodule_update_options_init`.
*
*/
typedef struct git_submodule_update_options {
* @param version The struct version; pass `GIT_SUBMODULE_UPDATE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_submodule_update_init_options(
+GIT_EXTERN(int) git_submodule_update_options_init(
git_submodule_update_options *opts, unsigned int version);
/**
* from the working directory to the new repo.
*
* To fully emulate "git submodule add" call this function, then open the
- * submodule repo and perform the clone step as needed. Lastly, call
+ * submodule repo and perform the clone step as needed (if you don't need
+ * anything custom see `git_submodule_add_clone()`). Lastly, call
* `git_submodule_add_finalize()` to wrap up adding the new submodule and
* .gitmodules to the index to be ready to commit.
*
const char *path,
int use_gitlink);
+/**
+ * Perform the clone step for a newly created submodule.
+ *
+ * This performs the necessary `git_clone` to setup a newly-created submodule.
+ *
+ * @param out The newly created repository object. Optional.
+ * @param submodule The submodule currently waiting for its clone.
+ * @param opts The options to use.
+ *
+ * @return 0 on success, -1 on other errors (see git_clone).
+ */
+GIT_EXTERN(int) git_submodule_clone(
+ git_repository **out,
+ git_submodule *submodule,
+ const git_submodule_update_options *opts);
+
/**
* Resolve the setup of a new git submodule.
*
* that all fields need to be set to a proper function.
*/
typedef struct {
- /* Allocate `n` bytes of memory */
+ /** Allocate `n` bytes of memory */
void * GIT_CALLBACK(gmalloc)(size_t n, const char *file, int line);
- /*
+ /**
* Allocate memory for an array of `nelem` elements, where each element
* has a size of `elsize`. Returned memory shall be initialized to
* all-zeroes
*/
void * GIT_CALLBACK(gcalloc)(size_t nelem, size_t elsize, const char *file, int line);
- /* Allocate memory for the string `str` and duplicate its contents. */
+ /** Allocate memory for the string `str` and duplicate its contents. */
char * GIT_CALLBACK(gstrdup)(const char *str, const char *file, int line);
- /*
+ /**
* Equivalent to the `gstrdup` function, but only duplicating at most
* `n + 1` bytes
*/
char * GIT_CALLBACK(gstrndup)(const char *str, size_t n, const char *file, int line);
- /*
+ /**
* Equivalent to `gstrndup`, but will always duplicate exactly `n` bytes
* of `str`. Thus, out of bounds reads at `str` may happen.
*/
char * GIT_CALLBACK(gsubstrdup)(const char *str, size_t n, const char *file, int line);
- /*
+ /**
* This function shall deallocate the old object `ptr` and return a
* pointer to a new object that has the size specified by `size`. In
* case `ptr` is `NULL`, a new array shall be allocated.
*/
void * GIT_CALLBACK(grealloc)(void *ptr, size_t size, const char *file, int line);
- /*
+ /**
* This function shall be equivalent to `grealloc`, but allocating
* `neleme * elsize` bytes.
*/
void * GIT_CALLBACK(greallocarray)(void *ptr, size_t nelem, size_t elsize, const char *file, int line);
- /*
+ /**
* This function shall allocate a new array of `nelem` elements, where
* each element has a size of `elsize` bytes.
*/
void * GIT_CALLBACK(gmallocarray)(size_t nelem, size_t elsize, const char *file, int line);
- /*
+ /**
* This function shall free the memory pointed to by `ptr`. In case
* `ptr` is `NULL`, this shall be a no-op.
*/
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_cred_h__
+#define INCLUDE_sys_git_cred_h__
+
+/* These declarations have moved. */
+#ifndef GIT_DEPRECATE_HARD
+# include "git2/sys/credential.h"
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_credential_h__
+#define INCLUDE_sys_git_credential_h__
+
+#include "git2/common.h"
+#include "git2/credential.h"
+
+/**
+ * @file git2/sys/cred.h
+ * @brief Git credentials low-level implementation
+ * @defgroup git_credential Git credentials low-level implementation
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * The base structure for all credential types
+ */
+struct git_credential {
+ git_credential_t credtype; /**< A type of credential */
+
+ /** The deallocator for this type of credentials */
+ void GIT_CALLBACK(free)(git_credential *cred);
+};
+
+/** A plaintext username and password */
+struct git_credential_userpass_plaintext {
+ git_credential parent; /**< The parent credential */
+ char *username; /**< The username to authenticate as */
+ char *password; /**< The password to use */
+};
+
+/** Username-only credential information */
+struct git_credential_username {
+ git_credential parent; /**< The parent credential */
+ char username[1]; /**< The username to authenticate as */
+};
+
+/**
+ * A ssh key from disk
+ */
+struct git_credential_ssh_key {
+ git_credential parent; /**< The parent credential */
+ char *username; /**< The username to authenticate as */
+ char *publickey; /**< The path to a public key */
+ char *privatekey; /**< The path to a private key */
+ char *passphrase; /**< Passphrase to decrypt the private key */
+};
+
+/**
+ * Keyboard-interactive based ssh authentication
+ */
+struct git_credential_ssh_interactive {
+ git_credential parent; /**< The parent credential */
+ char *username; /**< The username to authenticate as */
+
+ /**
+ * Callback used for authentication.
+ */
+ git_credential_ssh_interactive_cb prompt_callback;
+
+ void *payload; /**< Payload passed to prompt_callback */
+};
+
+/**
+ * A key with a custom signature function
+ */
+struct git_credential_ssh_custom {
+ git_credential parent; /**< The parent credential */
+ char *username; /**< The username to authenticate as */
+ char *publickey; /**< The public key data */
+ size_t publickey_len; /**< Length of the public key */
+
+ /**
+ * Callback used to sign the data.
+ */
+ git_credential_sign_cb sign_callback;
+
+ void *payload; /**< Payload passed to prompt_callback */
+};
+
+GIT_END_DECL
+
+#endif
* Remove all filename conflict entries.
*
* @param index an existing index object
+ * @return 0 or an error code
*/
-GIT_EXTERN(void) git_index_name_clear(git_index *index);
+GIT_EXTERN(int) git_index_name_clear(git_index *index);
/**@}*/
* Remove all resolve undo entries from the index
*
* @param index an existing index object
+ * @return 0 or an error code
*/
-GIT_EXTERN(void) git_index_reuc_clear(git_index *index);
+GIT_EXTERN(int) git_index_reuc_clear(git_index *index);
/**@}*/
* semantics to the Git repository.
*
* @param backend The mempack backend
+ * @return 0 on success; error code otherwise
*/
-GIT_EXTERN(void) git_mempack_reset(git_odb_backend *backend);
+GIT_EXTERN(int) git_mempack_reset(git_odb_backend *backend);
GIT_END_DECL
typedef struct git_merge_driver_source git_merge_driver_source;
/** Get the repository that the source data is coming from. */
-GIT_EXTERN(const git_repository *) git_merge_driver_source_repo(
+GIT_EXTERN(git_repository *) git_merge_driver_source_repo(
const git_merge_driver_source *src);
/** Gets the ancestor of the file to merge. */
/* read and read_prefix each return to libgit2 a buffer which
* will be freed later. The buffer should be allocated using
- * the function git_odb_backend_malloc to ensure that it can
- * be safely freed later. */
+ * the function git_odb_backend_data_alloc to ensure that libgit2
+ * can safely free it later. */
int GIT_CALLBACK(read)(
void **, size_t *, git_object_t *, git_odb_backend *, const git_oid *);
git_odb_backend *, const git_oid *, const void *, size_t, git_object_t);
int GIT_CALLBACK(writestream)(
- git_odb_stream **, git_odb_backend *, git_off_t, git_object_t);
+ git_odb_stream **, git_odb_backend *, git_object_size_t, git_object_t);
int GIT_CALLBACK(readstream)(
git_odb_stream **, size_t *, git_object_t *,
int GIT_CALLBACK(writepack)(
git_odb_writepack **, git_odb_backend *, git_odb *odb,
- git_transfer_progress_cb progress_cb, void *progress_payload);
+ git_indexer_progress_cb progress_cb, void *progress_payload);
/**
* "Freshens" an already existing object, updating its last-used
git_odb_backend *backend,
unsigned int version);
+/**
+ * Allocate data for an ODB object. Custom ODB backends may use this
+ * to provide data back to the ODB from their read function. This
+ * memory should not be freed once it is returned to libgit2. If a
+ * custom ODB uses this function but encounters an error and does not
+ * return this data to libgit2, then they should use the corresponding
+ * git_odb_backend_data_free function.
+ *
+ * @param backend the ODB backend that is allocating this memory
+ * @param len the number of bytes to allocate
+ * @return the allocated buffer on success or NULL if out of memory
+ */
+GIT_EXTERN(void *) git_odb_backend_data_alloc(git_odb_backend *backend, size_t len);
+
+/**
+ * Frees custom allocated ODB data. This should only be called when
+ * memory allocated using git_odb_backend_data_alloc is not returned
+ * to libgit2 because the backend encountered an error in the read
+ * function after allocation and did not return this data to libgit2.
+ *
+ * @param backend the ODB backend that is freeing this memory
+ * @param data the buffer to free
+ */
+GIT_EXTERN(void) git_odb_backend_data_free(git_odb_backend *backend, void *data);
+
+
+/*
+ * Users can avoid deprecated functions by defining `GIT_DEPRECATE_HARD`.
+ */
+#ifndef GIT_DEPRECATE_HARD
+
+/**
+ * Allocate memory for an ODB object from a custom backend. This is
+ * an alias of `git_odb_backend_data_alloc` and is preserved for
+ * backward compatibility.
+ *
+ * This function is deprecated, but there is no plan to remove this
+ * function at this time.
+ *
+ * @deprecated git_odb_backend_data_alloc
+ * @see git_odb_backend_data_alloc
+ */
GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len);
+#endif
+
GIT_END_DECL
#endif
/** An instance for a custom backend */
struct git_refdb_backend {
- unsigned int version;
+ unsigned int version; /**< The backend API version */
/**
- * Queries the refdb backend to determine if the given ref_name
- * exists. A refdb implementation must provide this function.
+ * Queries the refdb backend for the existence of a reference.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg exists The implementation shall set this to `0` if a ref does
+ * not exist, otherwise to `1`.
+ * @arg ref_name The reference's name that should be checked for
+ * existence.
+ * @return `0` on success, a negative error value code.
*/
int GIT_CALLBACK(exists)(
int *exists,
const char *ref_name);
/**
- * Queries the refdb backend for a given reference. A refdb
- * implementation must provide this function.
+ * Queries the refdb backend for a given reference.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg out The implementation shall set this to the allocated
+ * reference, if it could be found, otherwise to `NULL`.
+ * @arg ref_name The reference's name that should be checked for
+ * existence.
+ * @return `0` on success, `GIT_ENOTFOUND` if the reference does
+ * exist, otherwise a negative error code.
*/
int GIT_CALLBACK(lookup)(
git_reference **out,
* Allocate an iterator object for the backend.
*
* A refdb implementation must provide this function.
+ *
+ * @arg out The implementation shall set this to the allocated
+ * reference iterator. A custom structure may be used with an
+ * embedded `git_reference_iterator` structure. Both `next`
+ * and `next_name` functions of `git_reference_iterator` need
+ * to be populated.
+ * @arg glob A pattern to filter references by. If given, the iterator
+ * shall only return references that match the glob when
+ * passed to `wildmatch`.
+ * @return `0` on success, otherwise a negative error code.
*/
int GIT_CALLBACK(iterator)(
git_reference_iterator **iter,
struct git_refdb_backend *backend,
const char *glob);
- /*
- * Writes the given reference to the refdb. A refdb implementation
- * must provide this function.
+ /**
+ * Writes the given reference to the refdb.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg ref The reference to persist. May either be a symbolic or
+ * direct reference.
+ * @arg force Whether to write the reference if a reference with the
+ * same name already exists.
+ * @arg who The person updating the reference. Shall be used to create
+ * a reflog entry.
+ * @arg message The message detailing what kind of reference update is
+ * performed. Shall be used to create a reflog entry.
+ * @arg old If not `NULL` and `force` is not set, then the
+ * implementation needs to ensure that the reference is currently at
+ * the given OID before writing the new value. If both `old`
+ * and `old_target` are `NULL`, then the reference should not
+ * exist at the point of writing.
+ * @arg old_target If not `NULL` and `force` is not set, then the
+ * implementation needs to ensure that the symbolic
+ * reference is currently at the given target before
+ * writing the new value. If both `old` and
+ * `old_target` are `NULL`, then the reference should
+ * not exist at the point of writing.
+ * @return `0` on success, otherwise a negative error code.
*/
int GIT_CALLBACK(write)(git_refdb_backend *backend,
const git_reference *ref, int force,
const git_signature *who, const char *message,
const git_oid *old, const char *old_target);
+ /**
+ * Rename a reference in the refdb.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg out The implementation shall set this to the newly created
+ * reference or `NULL` on error.
+ * @arg old_name The current name of the reference that is to be renamed.
+ * @arg new_name The new name that the old reference shall be renamed to.
+ * @arg force Whether to write the reference if a reference with the
+ * target name already exists.
+ * @arg who The person updating the reference. Shall be used to create
+ * a reflog entry.
+ * @arg message The message detailing what kind of reference update is
+ * performed. Shall be used to create a reflog entry.
+ * @return `0` on success, otherwise a negative error code.
+ */
int GIT_CALLBACK(rename)(
git_reference **out, git_refdb_backend *backend,
const char *old_name, const char *new_name, int force,
const git_signature *who, const char *message);
/**
- * Deletes the given reference (and if necessary its reflog)
- * from the refdb. A refdb implementation must provide this
- * function.
+ * Deletes the given reference from the refdb.
+ *
+ * If it exists, its reflog should be deleted as well.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg ref_name The name of the reference name that shall be deleted.
+ * @arg old_id If not `NULL` and `force` is not set, then the
+ * implementation needs to ensure that the reference is currently at
+ * the given OID before writing the new value.
+ * @arg old_target If not `NULL` and `force` is not set, then the
+ * implementation needs to ensure that the symbolic
+ * reference is currently at the given target before
+ * writing the new value.
+ * @return `0` on success, otherwise a negative error code.
*/
int GIT_CALLBACK(del)(git_refdb_backend *backend, const char *ref_name, const git_oid *old_id, const char *old_target);
/**
* Suggests that the given refdb compress or optimize its references.
- * This mechanism is implementation specific. (For on-disk reference
- * databases, this may pack all loose references.) A refdb
- * implementation may provide this function; if it is not provided,
- * nothing will be done.
+ *
+ * This mechanism is implementation specific. For on-disk reference
+ * databases, this may pack all loose references.
+ *
+ * A refdb implementation may provide this function; if it is not
+ * provided, nothing will be done.
+ *
+ * @return `0` on success a negative error code otherwise
*/
int GIT_CALLBACK(compress)(git_refdb_backend *backend);
/**
* Query whether a particular reference has a log (may be empty)
+ *
+ * Shall return 1 if it has a reflog, 0 it it doesn't and negative in
+ * case an error occurred.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @return `0` on success, `1` if the reflog for the given reference
+ * exists, a negative error code otherwise
*/
int GIT_CALLBACK(has_log)(git_refdb_backend *backend, const char *refname);
/**
* Make sure a particular reference will have a reflog which
* will be appended to on writes.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(ensure_log)(git_refdb_backend *backend, const char *refname);
/**
* Frees any resources held by the refdb (including the `git_refdb_backend`
- * itself). A refdb backend implementation must provide this function.
+ * itself).
+ *
+ * A refdb backend implementation must provide this function.
*/
void GIT_CALLBACK(free)(git_refdb_backend *backend);
/**
* Read the reflog for the given reference name.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(reflog_read)(git_reflog **out, git_refdb_backend *backend, const char *name);
/**
* Write a reflog to disk.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg reflog The complete reference log for a given reference. Note
+ * that this may contain entries that have already been
+ * written to disk.
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(reflog_write)(git_refdb_backend *backend, git_reflog *reflog);
/**
- * Rename a reflog
+ * Rename a reflog.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg old_name The name of old reference whose reflog shall be renamed from.
+ * @arg new_name The name of new reference whose reflog shall be renamed to.
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(reflog_rename)(git_refdb_backend *_backend, const char *old_name, const char *new_name);
/**
* Remove a reflog.
+ *
+ * A refdb implementation must provide this function.
+ *
+ * @arg name The name of the reference whose reflog shall be deleted.
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(reflog_delete)(git_refdb_backend *backend, const char *name);
/**
- * Lock a reference. The opaque parameter will be passed to the unlock function
+ * Lock a reference.
+ *
+ * A refdb implementation may provide this function; if it is not
+ * provided, the transaction API will fail to work.
+ *
+ * @arg payload_out Opaque parameter that will be passed verbosely to
+ * `unlock`.
+ * @arg refname Reference that shall be locked.
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(lock)(void **payload_out, git_refdb_backend *backend, const char *refname);
/**
- * Unlock a reference. Only one of target or symbolic_target
- * will be set. success indicates whether to update the
- * reference or discard the lock (if it's false)
+ * Unlock a reference.
+ *
+ * Only one of target or symbolic_target will be set.
+ * `success` will be true if the reference should be update, false if
+ * the lock must be discarded.
+ *
+ * A refdb implementation must provide this function if a `lock`
+ * implementation is provided.
+ *
+ * @arg payload The payload returned by `lock`.
+ * @arg success `1` if a reference should be updated, `2` if
+ * a reference should be deleted, `0` if the lock must be
+ * discarded.
+ * @arg update_reflog `1` in case the reflog should be updated, `0`
+ * otherwise.
+ * @arg ref The reference which should be unlocked.
+ * @arg who The person updating the reference. Shall be used to create
+ * a reflog entry in case `update_reflog` is set.
+ * @arg message The message detailing what kind of reference update is
+ * performed. Shall be used to create a reflog entry in
+ * case `update_reflog` is set.
+ * @return `0` on success, a negative error code otherwise
*/
int GIT_CALLBACK(unlock)(git_refdb_backend *backend, void *payload, int success, int update_reflog,
const git_reference *ref, const git_signature *sig, const char *message);
* Note that this is only useful if you wish to associate the repository
* with a non-filesystem-backed object database and config store.
*
+ * Caveats: since this repository has no physical location, some systems
+ * can fail to function properly: locations under $GIT_DIR, $GIT_COMMON_DIR,
+ * or $GIT_INFO_DIR are impacted.
+ *
* @param out The blank repository
* @return 0 on success, or an error code
*/
* There's no need to call this function directly unless you're
* trying to aggressively cleanup the repo before its
* deallocation. `git_repository_free` already performs this operation
- * before deallocation the repo.
+ * before deallocating the repo.
+ *
+ * @param repo The repository to clean up
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_repository__cleanup(git_repository *repo);
+GIT_EXTERN(int) git_repository__cleanup(git_repository *repo);
/**
* Update the filesystem config settings for an open repository
*
* @param repo A repository object
* @param config A Config object
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config);
+GIT_EXTERN(int) git_repository_set_config(git_repository *repo, git_config *config);
/**
* Set the Object Database for this repository
*
* @param repo A repository object
* @param odb An ODB object
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb);
+GIT_EXTERN(int) git_repository_set_odb(git_repository *repo, git_odb *odb);
/**
* Set the Reference Database Backend for this repository
*
* @param repo A repository object
* @param refdb An refdb object
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_repository_set_refdb(git_repository *repo, git_refdb *refdb);
+GIT_EXTERN(int) git_repository_set_refdb(git_repository *repo, git_refdb *refdb);
/**
* Set the index file for this repository
*
* @param repo A repository object
* @param index An index object
+ * @return 0 on success, or an error code
*/
-GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index);
+GIT_EXTERN(int) git_repository_set_index(git_repository *repo, git_index *index);
/**
* Set a repository to be bare.
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_git_time_h__
-#define INCLUDE_git_time_h__
-
-#include "git2/common.h"
-
-GIT_BEGIN_DECL
-
-/**
- * Return a monotonic time value, useful for measuring running time
- * and setting up timeouts.
- *
- * The returned value is an arbitrary point in time -- it can only be
- * used when comparing it to another `git_time_monotonic` call.
- *
- * The time is returned in seconds, with a decimal fraction that differs
- * on accuracy based on the underlying system, but should be least
- * accurate to Nanoseconds.
- *
- * This function cannot fail.
- */
-GIT_EXTERN(double) git_time_monotonic(void);
-
-GIT_END_DECL
-#endif
-
int GIT_CALLBACK(connect)(
git_transport *transport,
const char *url,
- git_cred_acquire_cb cred_acquire_cb,
+ git_credential_acquire_cb cred_acquire_cb,
void *cred_acquire_payload,
const git_proxy_options *proxy_opts,
int direction,
int GIT_CALLBACK(download_pack)(
git_transport *transport,
git_repository *repo,
- git_transfer_progress *stats,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress *stats,
+ git_indexer_progress_cb progress_cb,
void *progress_payload);
/** Checks to see if the transport is connected */
* refused to provide credentials and callers should behave as if no
* callback was set), or < 0 for an error
*/
-GIT_EXTERN(int) git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods);
+GIT_EXTERN(int) git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods);
/**
* Get a copy of the proxy options
* @param force Overwrite existing tags
* @return 0 on success; error code otherwise
*/
-GIT_EXTERN(int) git_tag_create_frombuffer(
+GIT_EXTERN(int) git_tag_create_from_buffer(
git_oid *oid,
git_repository *repo,
const char *buffer,
const char *pattern,
git_repository *repo);
-
+/**
+ * Callback used to iterate over tag names
+ *
+ * @see git_tag_foreach
+ *
+ * @param name The tag name
+ * @param oid The tag's OID
+ * @param payload Payload passed to git_tag_foreach
+ * @return non-zero to terminate the iteration
+ */
typedef int GIT_CALLBACK(git_tag_foreach_cb)(const char *name, git_oid *oid, void *payload);
/**
/**
* An instance for a tracing function
*/
-typedef void GIT_CALLBACK(git_trace_callback)(git_trace_level_t level, const char *msg);
+typedef void GIT_CALLBACK(git_trace_cb)(git_trace_level_t level, const char *msg);
/**
* Sets the system tracing configuration to the specified level with the
* @param cb Function to call with trace data
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_trace_set(git_trace_level_t level, git_trace_callback cb);
+GIT_EXTERN(int) git_trace_set(git_trace_level_t level, git_trace_cb cb);
/** @} */
GIT_END_DECL
#include "indexer.h"
#include "net.h"
#include "types.h"
+#include "cert.h"
+#include "credential.h"
/**
* @file git2/transport.h
*/
GIT_BEGIN_DECL
-/** Signature of a function which creates a transport */
-typedef int GIT_CALLBACK(git_transport_cb)(git_transport **out, git_remote *owner, void *param);
-
-/**
- * Type of SSH host fingerprint
- */
-typedef enum {
- /** MD5 is available */
- GIT_CERT_SSH_MD5 = (1 << 0),
- /** SHA-1 is available */
- GIT_CERT_SSH_SHA1 = (1 << 1),
-} git_cert_ssh_t;
-
-/**
- * Hostkey information taken from libssh2
- */
-typedef struct {
- git_cert parent;
-
- /**
- * A hostkey type from libssh2, either
- * `GIT_CERT_SSH_MD5` or `GIT_CERT_SSH_SHA1`
- */
- git_cert_ssh_t type;
-
- /**
- * Hostkey hash. If type has `GIT_CERT_SSH_MD5` set, this will
- * have the MD5 hash of the hostkey.
- */
- unsigned char hash_md5[16];
-
- /**
- * Hostkey hash. If type has `GIT_CERT_SSH_SHA1` set, this will
- * have the SHA-1 hash of the hostkey.
- */
- unsigned char hash_sha1[20];
-} git_cert_hostkey;
-
-/**
- * X.509 certificate information
- */
-typedef struct {
- git_cert parent;
- /**
- * Pointer to the X.509 certificate data
- */
- void *data;
- /**
- * Length of the memory block pointed to by `data`.
- */
- size_t len;
-} git_cert_x509;
-
-/*
- *** Begin interface for credentials acquisition ***
- */
-
-/**
- * Supported credential types
- *
- * This represents the various types of authentication methods supported by
- * the library.
- */
-typedef enum {
- /**
- * A vanilla user/password request
- * @see git_cred_userpass_plaintext_new
- */
- GIT_CREDTYPE_USERPASS_PLAINTEXT = (1u << 0),
-
- /**
- * An SSH key-based authentication request
- * @see git_cred_ssh_key_new
- */
- GIT_CREDTYPE_SSH_KEY = (1u << 1),
-
- /**
- * An SSH key-based authentication request, with a custom signature
- * @see git_cred_ssh_custom_new
- */
- GIT_CREDTYPE_SSH_CUSTOM = (1u << 2),
-
- /**
- * An NTLM/Negotiate-based authentication request.
- * @see git_cred_default
- */
- GIT_CREDTYPE_DEFAULT = (1u << 3),
-
- /**
- * An SSH interactive authentication request
- * @see git_cred_ssh_interactive_new
- */
- GIT_CREDTYPE_SSH_INTERACTIVE = (1u << 4),
-
- /**
- * Username-only authentication request
- *
- * Used as a pre-authentication step if the underlying transport
- * (eg. SSH, with no username in its URL) does not know which username
- * to use.
- *
- * @see git_cred_username_new
- */
- GIT_CREDTYPE_USERNAME = (1u << 5),
-
- /**
- * An SSH key-based authentication request
- *
- * Allows credentials to be read from memory instead of files.
- * Note that because of differences in crypto backend support, it might
- * not be functional.
- *
- * @see git_cred_ssh_key_memory_new
- */
- GIT_CREDTYPE_SSH_MEMORY = (1u << 6),
-} git_credtype_t;
-
-typedef struct git_cred git_cred;
-
-/**
- * The base structure for all credential types
- */
-struct git_cred {
- git_credtype_t credtype; /**< A type of credential */
- void GIT_CALLBACK(free)(git_cred *cred);
-};
-
-/** A plaintext username and password */
-typedef struct {
- git_cred parent;
- char *username;
- char *password;
-} git_cred_userpass_plaintext;
-
-
-/*
- * If the user hasn't included libssh2.h before git2.h, we need to
- * define a few types for the callback signatures.
- */
-#ifndef LIBSSH2_VERSION
-typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
-typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT LIBSSH2_USERAUTH_KBDINT_PROMPT;
-typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE LIBSSH2_USERAUTH_KBDINT_RESPONSE;
-#endif
-
-typedef int GIT_CALLBACK(git_cred_sign_callback)(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract);
-typedef void GIT_CALLBACK(git_cred_ssh_interactive_callback)(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract);
-
-/**
- * A ssh key from disk
- */
-typedef struct git_cred_ssh_key {
- git_cred parent;
- char *username;
- char *publickey;
- char *privatekey;
- char *passphrase;
-} git_cred_ssh_key;
-
-/**
- * Keyboard-interactive based ssh authentication
- */
-typedef struct git_cred_ssh_interactive {
- git_cred parent;
- char *username;
- git_cred_ssh_interactive_callback prompt_callback;
- void *payload;
-} git_cred_ssh_interactive;
-
-/**
- * A key with a custom signature function
- */
-typedef struct git_cred_ssh_custom {
- git_cred parent;
- char *username;
- char *publickey;
- size_t publickey_len;
- git_cred_sign_callback sign_callback;
- void *payload;
-} git_cred_ssh_custom;
-
-/** A key for NTLM/Kerberos "default" credentials */
-typedef struct git_cred git_cred_default;
-
-/** Username-only credential information */
-typedef struct git_cred_username {
- git_cred parent;
- char username[1];
-} git_cred_username;
-
-/**
- * Check whether a credential object contains username information.
- *
- * @param cred object to check
- * @return 1 if the credential object has non-NULL username, 0 otherwise
- */
-GIT_EXTERN(int) git_cred_has_username(git_cred *cred);
-
-/**
- * Create a new plain-text username and password credential object.
- * The supplied credential parameter will be internally duplicated.
- *
- * @param out The newly created credential object.
- * @param username The username of the credential.
- * @param password The password of the credential.
- * @return 0 for success or an error code for failure
- */
-GIT_EXTERN(int) git_cred_userpass_plaintext_new(
- git_cred **out,
- const char *username,
- const char *password);
-
-/**
- * Create a new passphrase-protected ssh key credential object.
- * The supplied credential parameter will be internally duplicated.
- *
- * @param out The newly created credential object.
- * @param username username to use to authenticate
- * @param publickey The path to the public key of the credential.
- * @param privatekey The path to the private key of the credential.
- * @param passphrase The passphrase of the credential.
- * @return 0 for success or an error code for failure
- */
-GIT_EXTERN(int) git_cred_ssh_key_new(
- git_cred **out,
- const char *username,
- const char *publickey,
- const char *privatekey,
- const char *passphrase);
-
-/**
- * Create a new ssh keyboard-interactive based credential object.
- * The supplied credential parameter will be internally duplicated.
- *
- * @param username Username to use to authenticate.
- * @param prompt_callback The callback method used for prompts.
- * @param payload Additional data to pass to the callback.
- * @return 0 for success or an error code for failure.
- */
-GIT_EXTERN(int) git_cred_ssh_interactive_new(
- git_cred **out,
- const char *username,
- git_cred_ssh_interactive_callback prompt_callback,
- void *payload);
-
-/**
- * Create a new ssh key credential object used for querying an ssh-agent.
- * The supplied credential parameter will be internally duplicated.
- *
- * @param out The newly created credential object.
- * @param username username to use to authenticate
- * @return 0 for success or an error code for failure
- */
-GIT_EXTERN(int) git_cred_ssh_key_from_agent(
- git_cred **out,
- const char *username);
-
-/**
- * Create an ssh key credential with a custom signing function.
- *
- * This lets you use your own function to sign the challenge.
- *
- * This function and its credential type is provided for completeness
- * and wraps `libssh2_userauth_publickey()`, which is undocumented.
- *
- * The supplied credential parameter will be internally duplicated.
- *
- * @param out The newly created credential object.
- * @param username username to use to authenticate
- * @param publickey The bytes of the public key.
- * @param publickey_len The length of the public key in bytes.
- * @param sign_callback The callback method to sign the data during the challenge.
- * @param payload Additional data to pass to the callback.
- * @return 0 for success or an error code for failure
- */
-GIT_EXTERN(int) git_cred_ssh_custom_new(
- git_cred **out,
- const char *username,
- const char *publickey,
- size_t publickey_len,
- git_cred_sign_callback sign_callback,
- void *payload);
-
-/**
- * Create a "default" credential usable for Negotiate mechanisms like NTLM
- * or Kerberos authentication.
- *
- * @return 0 for success or an error code for failure
- */
-GIT_EXTERN(int) git_cred_default_new(git_cred **out);
-
-/**
- * Create a credential to specify a username.
- *
- * This is used with ssh authentication to query for the username if
- * none is specified in the url.
- */
-GIT_EXTERN(int) git_cred_username_new(git_cred **cred, const char *username);
-
-/**
- * Create a new ssh key credential object reading the keys from memory.
- *
- * @param out The newly created credential object.
- * @param username username to use to authenticate.
- * @param publickey The public key of the credential.
- * @param privatekey The private key of the credential.
- * @param passphrase The passphrase of the credential.
- * @return 0 for success or an error code for failure
- */
-GIT_EXTERN(int) git_cred_ssh_key_memory_new(
- git_cred **out,
- const char *username,
- const char *publickey,
- const char *privatekey,
- const char *passphrase);
-
-
/**
- * Free a credential.
+ * Callback for messages recieved by the transport.
*
- * This is only necessary if you own the object; that is, if you are a
- * transport.
+ * Return a negative value to cancel the network operation.
*
- * @param cred the object to free
+ * @param str The message from the transport
+ * @param len The length of the message
+ * @param payload Payload provided by the caller
*/
-GIT_EXTERN(void) git_cred_free(git_cred *cred);
+typedef int GIT_CALLBACK(git_transport_message_cb)(const char *str, int len, void *payload);
-/**
- * Signature of a function which acquires a credential object.
- *
- * @param cred The newly created credential object.
- * @param url The resource for which we are demanding a credential.
- * @param username_from_url The username that was embedded in a "user\@host"
- * remote url, or NULL if not included.
- * @param allowed_types A bitmask stating which cred types are OK to return.
- * @param payload The payload provided when specifying this callback.
- * @return 0 for success, < 0 to indicate an error, > 0 to indicate
- * no credential was acquired
- */
-typedef int GIT_CALLBACK(git_cred_acquire_cb)(
- git_cred **cred,
- const char *url,
- const char *username_from_url,
- unsigned int allowed_types,
- void *payload);
+/** Signature of a function which creates a transport */
+typedef int GIT_CALLBACK(git_transport_cb)(git_transport **out, git_remote *owner, void *param);
/** @} */
GIT_END_DECL
+
#endif
* Clear all the entires in the builder
*
* @param bld Builder to clear
+ * @return 0 on success; error code otherwise
*/
-GIT_EXTERN(void) git_treebuilder_clear(git_treebuilder *bld);
+GIT_EXTERN(int) git_treebuilder_clear(git_treebuilder *bld);
/**
* Get the number of entries listed in a treebuilder
* @param bld a previously loaded treebuilder.
* @return the number of entries in the treebuilder
*/
-GIT_EXTERN(unsigned int) git_treebuilder_entrycount(git_treebuilder *bld);
+GIT_EXTERN(size_t) git_treebuilder_entrycount(git_treebuilder *bld);
/**
* Free a tree builder
* @param bld Tree builder
* @param filter Callback to filter entries
* @param payload Extra data to pass to filter callback
+ * @return 0 on success, non-zero callback return value, or error code
*/
-GIT_EXTERN(void) git_treebuilder_filter(
+GIT_EXTERN(int) git_treebuilder_filter(
git_treebuilder *bld,
git_treebuilder_filter_cb filter,
void *payload);
#endif
+/** The maximum size of an object */
+typedef uint64_t git_object_size_t;
+
#include "buffer.h"
#include "oid.h"
typedef struct git_remote_head git_remote_head;
typedef struct git_remote_callbacks git_remote_callbacks;
-/**
- * This is passed as the first argument to the callback to allow the
- * user to see the progress.
- *
- * - total_objects: number of objects in the packfile being downloaded
- * - indexed_objects: received objects that have been hashed
- * - received_objects: objects which have been downloaded
- * - local_objects: locally-available objects that have been injected
- * in order to fix a thin pack.
- * - received-bytes: size of the packfile received up to now
- */
-typedef struct git_transfer_progress {
- unsigned int total_objects;
- unsigned int indexed_objects;
- unsigned int received_objects;
- unsigned int local_objects;
- unsigned int total_deltas;
- unsigned int indexed_deltas;
- size_t received_bytes;
-} git_transfer_progress;
-
-/**
- * Type for progress callbacks during indexing. Return a value less than zero
- * to cancel the transfer.
- *
- * @param stats Structure containing information about the state of the transfer
- * @param payload Payload provided by caller
- */
-typedef int GIT_CALLBACK(git_transfer_progress_cb)(const git_transfer_progress *stats, void *payload);
-
-/**
- * Type for messages delivered by the transport. Return a negative value
- * to cancel the network operation.
- *
- * @param str The message from the transport
- * @param len The length of the message
- * @param payload Payload provided by the caller
- */
-typedef int GIT_CALLBACK(git_transport_message_cb)(const char *str, int len, void *payload);
-
-
-/**
- * Type of host certificate structure that is passed to the check callback
- */
-typedef enum git_cert_t {
- /**
- * No information about the certificate is available. This may
- * happen when using curl.
- */
- GIT_CERT_NONE,
- /**
- * The `data` argument to the callback will be a pointer to
- * the DER-encoded data.
- */
- GIT_CERT_X509,
- /**
- * The `data` argument to the callback will be a pointer to a
- * `git_cert_hostkey` structure.
- */
- GIT_CERT_HOSTKEY_LIBSSH2,
- /**
- * The `data` argument to the callback will be a pointer to a
- * `git_strarray` with `name:content` strings containing
- * information about the certificate. This is used when using
- * curl.
- */
- GIT_CERT_STRARRAY,
-} git_cert_t;
-
/**
* Parent type for `git_cert_hostkey` and `git_cert_x509`.
*/
-typedef struct {
- /**
- * Type of certificate. A `GIT_CERT_` value.
- */
- git_cert_t cert_type;
-} git_cert;
-
-/**
- * Callback for the user's custom certificate checks.
- *
- * @param cert The host certificate
- * @param valid Whether the libgit2 checks (OpenSSL or WinHTTP) think
- * this certificate is valid
- * @param host Hostname of the host libgit2 connected to
- * @param payload Payload provided by the caller
- * @return 0 to proceed with the connection, < 0 to fail the connection
- * or > 0 to indicate that the callback refused to act and that
- * the existing validity determination should be honored
- */
-typedef int GIT_CALLBACK(git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload);
+typedef struct git_cert git_cert;
/**
* Opaque structure representing a submodule.
#ifndef INCLUDE_git_version_h__
#define INCLUDE_git_version_h__
-#define LIBGIT2_VERSION "0.28.4"
-#define LIBGIT2_VER_MAJOR 0
-#define LIBGIT2_VER_MINOR 28
-#define LIBGIT2_VER_REVISION 4
+#define LIBGIT2_VERSION "1.1.0"
+#define LIBGIT2_VER_MAJOR 1
+#define LIBGIT2_VER_MINOR 1
+#define LIBGIT2_VER_REVISION 0
#define LIBGIT2_VER_PATCH 0
-#define LIBGIT2_SOVERSION 28
+#define LIBGIT2_SOVERSION "1.1"
#endif
* Worktree add options structure
*
* Initialize with `GIT_WORKTREE_ADD_OPTIONS_INIT`. Alternatively, you can
- * use `git_worktree_add_init_options`.
+ * use `git_worktree_add_options_init`.
*
*/
typedef struct git_worktree_add_options {
* @param version The struct version; pass `GIT_WORKTREE_ADD_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_worktree_add_init_options(git_worktree_add_options *opts,
+GIT_EXTERN(int) git_worktree_add_options_init(git_worktree_add_options *opts,
unsigned int version);
/**
* is valid for the lifetime of the git_worktree.
*/
GIT_EXTERN(const char *) git_worktree_path(const git_worktree *wt);
-
+
/**
* Flags which can be passed to git_worktree_prune to alter its
* behavior.
* Worktree prune options structure
*
* Initialize with `GIT_WORKTREE_PRUNE_OPTIONS_INIT`. Alternatively, you can
- * use `git_worktree_prune_init_options`.
+ * use `git_worktree_prune_options_init`.
*
*/
typedef struct git_worktree_prune_options {
* @param version The struct version; pass `GIT_WORKTREE_PRUNE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
-GIT_EXTERN(int) git_worktree_prune_init_options(
+GIT_EXTERN(int) git_worktree_prune_options_init(
git_worktree_prune_options *opts,
unsigned int version);
+++ /dev/null
-prefix="@PKGCONFIG_PREFIX@"
-libdir=@PKGCONFIG_LIBDIR@
-includedir=@PKGCONFIG_INCLUDEDIR@
-
-Name: libgit2
-Description: The git library, take 2
-Version: @LIBGIT2_VERSION_STRING@
-
-Libs: -L${libdir} -lgit2
-Libs.private: @LIBGIT2_PC_LIBS@
-Requires.private: @LIBGIT2_PC_REQUIRES@
-
-Cflags: -I${includedir}
+++ /dev/null
-{
- ignore-zlib-errors-cond
- Memcheck:Cond
- obj:*libz.so*
-}
-
-{
- ignore-giterror-set-leak
- Memcheck:Leak
- ...
- fun:giterror_set
-}
-
-{
- ignore-git-global-state-leak
- Memcheck:Leak
- ...
- fun:git__global_state
-}
-
-{
- ignore-openssl-ssl-leak
- Memcheck:Leak
- ...
- obj:*libssl.so*
- ...
-}
-
-{
- ignore-openssl-crypto-leak
- Memcheck:Leak
- ...
- obj:*libcrypto.so*
- ...
-}
-
-{
- ignore-openssl-crypto-cond
- Memcheck:Cond
- obj:*libcrypto.so*
- ...
-}
-
-{
- ignore-glibc-getaddrinfo-cache
- Memcheck:Leak
- ...
- fun:__check_pf
-}
-
-{
- ignore-curl-global-init
- Memcheck:Leak
- ...
- fun:curl_global_init
-}
-
-{
- ignore-libssh2-gcrypt-control-leak
- Memcheck:Leak
- ...
- fun:gcry_control
- obj:*libssh2.so*
-}
-
-{
- ignore-libssh2-gcrypt-mpinew-leak
- Memcheck:Leak
- ...
- fun:gcry_mpi_new
- obj:*libssh2.so*
-}
-
-{
- ignore-libssh2-gcrypt-mpiscan-leak
- Memcheck:Leak
- ...
- fun:gcry_mpi_scan
- obj:*libssh2.so*
-}
-
-{
- ignore-libssh2-gcrypt-randomize-leak
- Memcheck:Leak
- ...
- fun:gcry_randomize
- obj:*libssh2.so*
-}
-
-{
- ignore-libssh2-gcrypt-sexpfindtoken-leak
- Memcheck:Leak
- ...
- fun:gcry_sexp_find_token
- obj:*libssh2.so*
-}
-
-{
- ignore-libssh2-gcrypt-pksign-leak
- Memcheck:Leak
- ...
- fun:gcry_pk_sign
- obj:*libssh2.so*
-}
-
-{
- ignore-noai6ai_cached-double-free
- Memcheck:Free
- fun:free
- fun:__libc_freeres
- ...
- fun:exit
- ...
-}
{
"name": "libgit2",
- "version": "0.27.0",
+ "version": "1.1.0",
"repo": "https://github.com/libgit2/libgit2",
"description": " A cross-platform, linkable library implementation of Git that you can use in your application.",
"install": "mkdir build && cd build && cmake .. && cmake --build ."
--- /dev/null
+#!/bin/sh
+export MallocStackLogging=1
+export MallocScribble=1
+export MallocLogFile=/dev/null
+export CLAR_AT_EXIT="leaks -quiet \$PPID"
+exec "$@"
--- /dev/null
+#!/usr/bin/env python
+
+from collections import namedtuple
+
+import argparse
+import base64
+import copy
+import json
+import subprocess
+import sys
+import urllib.parse
+import urllib.request
+import urllib.error
+
+class Error(Exception):
+ pass
+
+class Version(object):
+ def __init__(self, version):
+ versions = version.split(sep='.')
+ if len(versions) < 2 or len(versions) > 3:
+ raise Error("Invalid version string '{}'".format(version))
+ self.major = int(versions[0])
+ self.minor = int(versions[1])
+ self.revision = int(versions[2]) if len(versions) == 3 else 0
+
+ def __str__(self):
+ return '{}.{}.{}'.format(self.major, self.minor, self.revision)
+
+ def __eq__(self, other):
+ return self.major == other.major and self.minor == other.minor and self.revision == other.revision
+
+def verify_version(version):
+ expected = {
+ 'VERSION': [ '"{}"'.format(version), None ],
+ 'VER_MAJOR': [ str(version.major), None ],
+ 'VER_MINOR': [ str(version.minor), None ],
+ 'VER_REVISION': [ str(version.revision), None ],
+ 'VER_PATCH': [ '0', None ],
+ 'SOVERSION': [ '"{}.{}"'.format(version.major, version.minor), None ],
+ }
+
+ # Parse CMakeLists
+ with open('CMakeLists.txt') as f:
+ for line in f.readlines():
+ if line.startswith('project(libgit2 VERSION "{}"'.format(version)):
+ break
+ else:
+ raise Error("cmake: invalid project definition")
+
+ # Parse version.h
+ with open('include/git2/version.h') as f:
+ lines = f.readlines()
+
+ for key in expected.keys():
+ define = '#define LIBGIT2_{} '.format(key)
+ for line in lines:
+ if line.startswith(define):
+ expected[key][1] = line[len(define):].strip()
+ break
+ else:
+ raise Error("version.h: missing define for '{}'".format(key))
+
+ for k, v in expected.items():
+ if v[0] != v[1]:
+ raise Error("version.h: define '{}' does not match (got '{}', expected '{}')".format(k, v[0], v[1]))
+
+ with open('package.json') as f:
+ pkg = json.load(f)
+
+ try:
+ pkg_version = Version(pkg["version"])
+ except KeyError as err:
+ raise Error("package.json: missing the field {}".format(err))
+
+ if pkg_version != version:
+ raise Error("package.json: version does not match (got '{}', expected '{}')".format(pkg_version, version))
+
+def generate_relnotes(tree, version):
+ with open('docs/changelog.md') as f:
+ lines = f.readlines()
+
+ if not lines[0].startswith('v'):
+ raise Error("changelog.md: missing section for v{}".format(version))
+ try:
+ v = Version(lines[0][1:].strip())
+ except:
+ raise Error("changelog.md: invalid version string {}".format(lines[0].strip()))
+ if v != version:
+ raise Error("changelog.md: changelog version doesn't match (got {}, expected {})".format(v, version))
+ if not lines[1].startswith('----'):
+ raise Error("changelog.md: missing version header")
+ if lines[2] != '\n':
+ raise Error("changelog.md: missing newline after version header")
+
+ for i, line in enumerate(lines[3:]):
+ if not line.startswith('v'):
+ continue
+ try:
+ Version(line[1:].strip())
+ break
+ except:
+ continue
+ else:
+ raise Error("changelog.md: cannot find section header of preceding release")
+
+ return ''.join(lines[3:i + 3]).strip()
+
+def git(*args):
+ process = subprocess.run([ 'git', *args ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if process.returncode != 0:
+ raise Error('Failed executing git {}: {}'.format(' '.join(args), process.stderr.decode()))
+ return process.stdout
+
+def post(url, data, contenttype, user, password):
+ request = urllib.request.Request(url, data=data)
+ request.add_header('Accept', 'application/json')
+ request.add_header('Content-Type', contenttype)
+ request.add_header('Content-Length', len(data))
+ request.add_header('Authorization', 'Basic ' + base64.b64encode('{}:{}'.format(user, password).encode()).decode())
+
+ try:
+ response = urllib.request.urlopen(request)
+ if response.getcode() != 201:
+ raise Error("POST to '{}' failed: {}".format(url, response.reason))
+ except urllib.error.URLError as e:
+ raise Error("POST to '{}' failed: {}".format(url, e))
+ data = json.load(response)
+
+ return data
+
+def generate_asset(version, tree, archive_format):
+ Asset = namedtuple('Asset', ['name', 'label', 'mimetype', 'data'])
+ mimetype = 'application/{}'.format('gzip' if archive_format == 'tar.gz' else 'zip')
+ return Asset(
+ "libgit2-{}.{}".format(version, archive_format), "Release sources: libgit2-{}.{}".format(version, archive_format), mimetype,
+ git('archive', '--format', archive_format, '--prefix', 'libgit2-{}/'.format(version), tree)
+ )
+
+def release(args):
+ params = {
+ "tag_name": 'v' + str(args.version),
+ "name": 'libgit2 v' + str(args.version),
+ "target_commitish": git('rev-parse', args.tree).decode().strip(),
+ "body": generate_relnotes(args.tree, args.version),
+ }
+ assets = [
+ generate_asset(args.version, args.tree, 'tar.gz'),
+ generate_asset(args.version, args.tree, 'zip'),
+ ]
+
+ if args.dryrun:
+ for k, v in params.items():
+ print('{}: {}'.format(k, v))
+ for asset in assets:
+ print('asset: name={}, label={}, mimetype={}, bytes={}'.format(asset.name, asset.label, asset.mimetype, len(asset.data)))
+ return
+
+ try:
+ url = 'https://api.github.com/repos/{}/releases'.format(args.repository)
+ response = post(url, json.dumps(params).encode(), 'application/json', args.user, args.password)
+ except Error as e:
+ raise Error('Could not create release: ' + str(e))
+
+ for asset in assets:
+ try:
+ url = list(urllib.parse.urlparse(response['upload_url'].split('{?')[0]))
+ url[4] = urllib.parse.urlencode({ 'name': asset.name, 'label': asset.label })
+ post(urllib.parse.urlunparse(url), asset.data, asset.mimetype, args.user, args.password)
+ except Error as e:
+ raise Error('Could not upload asset: ' + str(e))
+
+def main():
+ parser = argparse.ArgumentParser(description='Create a libgit2 release')
+ parser.add_argument('--tree', default='HEAD', help='tree to create release for (default: HEAD)')
+ parser.add_argument('--dryrun', action='store_true', help='generate release, but do not post it')
+ parser.add_argument('--repository', default='libgit2/libgit2', help='GitHub repository to create repository in')
+ parser.add_argument('--user', help='user to authenticate as')
+ parser.add_argument('--password', help='password to authenticate with')
+ parser.add_argument('version', type=Version, help='version of the new release')
+ args = parser.parse_args()
+
+ verify_version(args.version)
+ release(args)
+
+if __name__ == '__main__':
+ try:
+ main()
+ except Error as e:
+ print(e)
+ sys.exit(1)
--- /dev/null
+[undefined]
+# This library allows unaligned access on Intel-like processors. Prevent UBSan
+# from complaining about that.
+fun:sha1_compression_states
--- /dev/null
+#!/bin/bash
+exec valgrind --leak-check=full --show-reachable=yes --error-exitcode=125 --num-callers=50 --suppressions="$(dirname "${BASH_SOURCE[0]}")/valgrind.supp" "$@"
--- /dev/null
+{
+ ignore-zlib-errors-cond
+ Memcheck:Cond
+ obj:*libz.so*
+}
+
+{
+ ignore-giterror-set-leak
+ Memcheck:Leak
+ ...
+ fun:giterror_set
+}
+
+{
+ ignore-git-global-state-leak
+ Memcheck:Leak
+ ...
+ fun:git__global_state
+}
+
+{
+ ignore-openssl-ssl-leak
+ Memcheck:Leak
+ ...
+ obj:*libssl.so*
+ ...
+}
+
+{
+ ignore-openssl-crypto-leak
+ Memcheck:Leak
+ ...
+ obj:*libcrypto.so*
+ ...
+}
+
+{
+ ignore-openssl-crypto-cond
+ Memcheck:Cond
+ obj:*libcrypto.so*
+ ...
+}
+
+{
+ ignore-glibc-getaddrinfo-cache
+ Memcheck:Leak
+ ...
+ fun:__check_pf
+}
+
+{
+ ignore-curl-global-init
+ Memcheck:Leak
+ ...
+ fun:curl_global_init
+}
+
+{
+ ignore-libssh2-init
+ Memcheck:Leak
+ ...
+ fun:gcry_control
+ fun:libssh2_init
+ ...
+}
+
+{
+ ignore-libssh2-gcrypt-control-leak
+ Memcheck:Leak
+ ...
+ fun:gcry_control
+ obj:*libssh2.so*
+}
+
+{
+ ignore-libssh2-gcrypt-mpinew-leak
+ Memcheck:Leak
+ ...
+ fun:gcry_mpi_new
+ obj:*libssh2.so*
+}
+
+{
+ ignore-libssh2-gcrypt-mpiscan-leak
+ Memcheck:Leak
+ ...
+ fun:gcry_mpi_scan
+ obj:*libssh2.so*
+ ...
+}
+
+{
+ ignore-libssh2-gcrypt-randomize-leak
+ Memcheck:Leak
+ ...
+ fun:gcry_randomize
+ obj:*libssh2.so*
+}
+
+{
+ ignore-libssh2-gcrypt-sexpfindtoken-leak
+ Memcheck:Leak
+ ...
+ fun:gcry_sexp_find_token
+ obj:*libssh2.so*
+}
+
+{
+ ignore-libssh2-gcrypt-pksign-leak
+ Memcheck:Leak
+ ...
+ fun:gcry_pk_sign
+ obj:*libssh2.so*
+}
+
+{
+ ignore-libssh2-gcrypt-session-handshake
+ Memcheck:Leak
+ ...
+ obj:*libssh2.so*
+ obj:*libssh2.so*
+ fun:libssh2_session_handshake
+ ...
+}
+
+{
+ ignore-openssl-undefined-in-read
+ Memcheck:Cond
+ ...
+ obj:*libssl.so*
+ ...
+ fun:openssl_read
+ ...
+}
+
+{
+ ignore-openssl-undefined-in-connect
+ Memcheck:Cond
+ ...
+ obj:*libssl.so*
+ ...
+ fun:openssl_connect
+ ...
+}
+
+{
+ ignore-libssh2-rsa-sha1-sign
+ Memcheck:Leak
+ ...
+ obj:*libgcrypt.so*
+ fun:_libssh2_rsa_sha1_sign
+ ...
+}
+
+{
+ ignore-libssh2-kexinit
+ Memcheck:Leak
+ ...
+ obj:*libssh2.so*
+ fun:kexinit
+ ...
+}
+
+{
+ ignore-noai6ai_cached-double-free
+ Memcheck:Free
+ fun:free
+ fun:__libc_freeres
+ ...
+ fun:exit
+ ...
+}
+
+{
+ ignore-libcrypto-uninitialized-read-for-entropy
+ Memcheck:Value8
+ ...
+ obj:*libcrypto.so*
+ ...
+}
+add_library(git2internal OBJECT)
+set_target_properties(git2internal PROPERTIES C_STANDARD 90)
+
IF(DEBUG_POOL)
SET(GIT_DEBUG_POOL 1)
ENDIF()
ADD_FEATURE_INFO(debugpool GIT_DEBUG_POOL "debug pool allocator")
+INCLUDE(PkgBuildConfig)
+
# This variable will contain the libraries we need to put into
# libgit2.pc's Requires.private. That is, what we're linking to or
# what someone who's statically linking us needs to link to.
SET(LIBGIT2_SYSTEM_INCLUDES "")
SET(LIBGIT2_LIBS "")
-# Installation paths
-#
-SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.")
-SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.")
-SET(INCLUDE_INSTALL_DIR include CACHE PATH "Where to install headers to.")
-
-# Set a couple variables to be substituted inside the .pc file.
-# We can't just use LIB_INSTALL_DIR in the .pc file, as passing them as absolue
-# or relative paths is both valid and supported by cmake.
-SET (PKGCONFIG_PREFIX ${CMAKE_INSTALL_PREFIX})
-
-IF(IS_ABSOLUTE ${LIB_INSTALL_DIR})
- SET (PKGCONFIG_LIBDIR ${LIB_INSTALL_DIR})
-ELSE(IS_ABSOLUTE ${LIB_INSTALL_DIR})
- SET (PKGCONFIG_LIBDIR "\${prefix}/${LIB_INSTALL_DIR}")
-ENDIF (IS_ABSOLUTE ${LIB_INSTALL_DIR})
-
-IF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
- SET (PKGCONFIG_INCLUDEDIR ${INCLUDE_INSTALL_DIR})
-ELSE(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
- SET (PKGCONFIG_INCLUDEDIR "\${prefix}/${INCLUDE_INSTALL_DIR}")
-ENDIF(IS_ABSOLUTE ${INCLUDE_INSTALL_DIR})
+enable_warnings(missing-declarations)
# Enable tracing
-IF (ENABLE_TRACE STREQUAL "ON")
+IF(ENABLE_TRACE)
SET(GIT_TRACE 1)
ENDIF()
ADD_FEATURE_INFO(tracing GIT_TRACE "tracing support")
-# Use `regcomp_l` if available
-CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
-IF (HAVE_REGCOMP_L)
- SET(GIT_USE_REGCOMP_L 1)
-ENDIF ()
-
-# Otherwise, we either want to use system's `regcomp` or our
-# bundled regcomp code, if system doesn't provide `regcomp`.
-IF(NOT HAVE_REGCOMP_L)
- CHECK_FUNCTION_EXISTS(regcomp HAVE_REGCOMP)
- IF(NOT HAVE_REGCOMP)
- ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/regex" "${libgit2_BINARY_DIR}/deps/regex")
- LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/regex")
- LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:regex>)
- ENDIF()
-ENDIF()
-
CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
IF (HAVE_FUTIMENS)
SET(GIT_USE_FUTIMENS 1)
"void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compar)(void *, const void *, const void *))"
"" "stdlib.h" HAVE_QSORT_R_BSD)
IF (HAVE_QSORT_R_BSD)
- ADD_DEFINITIONS(-DHAVE_QSORT_R_BSD)
+ target_compile_definitions(git2internal PRIVATE HAVE_QSORT_R_BSD)
ENDIF()
CHECK_PROTOTYPE_DEFINITION(qsort_r
"void qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg)"
"" "stdlib.h" HAVE_QSORT_R_GNU)
IF (HAVE_QSORT_R_GNU)
- ADD_DEFINITIONS(-DHAVE_QSORT_R_GNU)
+ target_compile_definitions(git2internal PRIVATE HAVE_QSORT_R_GNU)
ENDIF()
CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S)
IF (HAVE_QSORT_S)
- ADD_DEFINITIONS(-DHAVE_QSORT_S)
+ target_compile_definitions(git2internal PRIVATE HAVE_QSORT_S)
ENDIF ()
# Find required dependencies
ADD_FEATURE_INFO(threadsafe THREADSAFE "threadsafe support")
-IF (WIN32 AND EMBED_SSH_PATH)
- FILE(GLOB SRC_SSH "${EMBED_SSH_PATH}/src/*.c")
- LIST(APPEND LIBGIT2_SYSTEM_INCLUDES "${EMBED_SSH_PATH}/include")
- FILE(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"")
- SET(GIT_SSH 1)
-ENDIF()
+if(WIN32 AND EMBED_SSH_PATH)
+ file(GLOB SRC_SSH "${EMBED_SSH_PATH}/src/*.c")
+ list(SORT SRC_SSH)
+ target_sources(git2internal PRIVATE ${SRC_SSH})
+
+ list(APPEND LIBGIT2_SYSTEM_INCLUDES "${EMBED_SSH_PATH}/include")
+ file(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"")
+ set(GIT_SSH 1)
+endif()
IF (WIN32 AND WINHTTP)
SET(GIT_WINHTTP 1)
LIST(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32")
ENDIF()
-IF (USE_HTTPS)
- # We try to find any packages our backends might use
- FIND_PACKAGE(OpenSSL)
- FIND_PACKAGE(mbedTLS)
- IF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
- FIND_PACKAGE(Security)
- FIND_PACKAGE(CoreFoundation)
- ENDIF()
+include(SelectHTTPSBackend)
+include(SelectHashes)
+target_sources(git2internal PRIVATE ${SRC_SHA1})
- # Auto-select TLS backend
- IF (USE_HTTPS STREQUAL ON)
- IF (SECURITY_FOUND)
- IF (SECURITY_HAS_SSLCREATECONTEXT)
- SET(HTTPS_BACKEND "SecureTransport")
- ELSE()
- MESSAGE("-- Security framework is too old, falling back to OpenSSL")
- SET(HTTPS_BACKEND "OpenSSL")
- ENDIF()
- ELSEIF (WINHTTP)
- SET(HTTPS_BACKEND "WinHTTP")
- ELSEIF(OPENSSL_FOUND)
- SET(HTTPS_BACKEND "OpenSSL")
- ELSEIF(MBEDTLS_FOUND)
- SET(HTTPS_BACKEND "mbedTLS")
- ELSE()
- MESSAGE(FATAL_ERROR "Unable to autodetect a usable HTTPS backend."
- "Please pass the backend name explicitly (-DUSE_HTTPS=backend)")
- ENDIF()
- ELSE()
- # Backend was explicitly set
- SET(HTTPS_BACKEND ${USE_HTTPS})
- ENDIF()
+# Specify regular expression implementation
+FIND_PACKAGE(PCRE)
- # Check that we can find what's required for the selected backend
- IF (HTTPS_BACKEND STREQUAL "SecureTransport")
- IF (NOT COREFOUNDATION_FOUND)
- MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, CoreFoundation.framework not found")
- ENDIF()
- IF (NOT SECURITY_FOUND)
- MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, Security.framework not found")
- ENDIF()
- IF (NOT SECURITY_HAS_SSLCREATECONTEXT)
- MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, SSLCreateContext not supported")
- ENDIF()
+IF(REGEX_BACKEND STREQUAL "")
+ CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
- SET(GIT_SECURE_TRANSPORT 1)
- LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR})
- LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_LIBRARIES} ${SECURITY_LIBRARIES})
- LIST(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS})
- ELSEIF (HTTPS_BACKEND STREQUAL "OpenSSL")
- IF (NOT OPENSSL_FOUND)
- MESSAGE(FATAL_ERROR "Asked for OpenSSL TLS backend, but it wasn't found")
- ENDIF()
-
- SET(GIT_OPENSSL 1)
- LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR})
- LIST(APPEND LIBGIT2_LIBS ${OPENSSL_LIBRARIES})
- LIST(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS})
- LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
- ELSEIF(HTTPS_BACKEND STREQUAL "mbedTLS")
- IF (NOT MBEDTLS_FOUND)
- MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found")
- ENDIF()
-
- IF(NOT CERT_LOCATION)
- MESSAGE("Auto-detecting default certificates location")
- IF(CMAKE_SYSTEM_NAME MATCHES Darwin)
- # Check for an Homebrew installation
- SET(OPENSSL_CMD "/usr/local/opt/openssl/bin/openssl")
- ELSE()
- SET(OPENSSL_CMD "openssl")
- ENDIF()
- EXECUTE_PROCESS(COMMAND ${OPENSSL_CMD} version -d OUTPUT_VARIABLE OPENSSL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
- IF(OPENSSL_DIR)
- STRING(REGEX REPLACE "^OPENSSLDIR: \"(.*)\"$" "\\1/" OPENSSL_DIR ${OPENSSL_DIR})
-
- SET(OPENSSL_CA_LOCATIONS
- "ca-bundle.pem" # OpenSUSE Leap 42.1
- "cert.pem" # Ubuntu 14.04, FreeBSD
- "certs/ca-certificates.crt" # Ubuntu 16.04
- "certs/ca.pem" # Debian 7
- )
- FOREACH(SUFFIX IN LISTS OPENSSL_CA_LOCATIONS)
- SET(LOC "${OPENSSL_DIR}${SUFFIX}")
- IF(NOT CERT_LOCATION AND EXISTS "${OPENSSL_DIR}${SUFFIX}")
- SET(CERT_LOCATION ${LOC})
- ENDIF()
- ENDFOREACH()
- ELSE()
- MESSAGE("Unable to find OpenSSL executable. Please provide default certificate location via CERT_LOCATION")
- ENDIF()
- ENDIF()
-
- IF(CERT_LOCATION)
- IF(NOT EXISTS ${CERT_LOCATION})
- MESSAGE(FATAL_ERROR "Cannot use CERT_LOCATION=${CERT_LOCATION} as it doesn't exist")
- ENDIF()
- ADD_FEATURE_INFO(CERT_LOCATION ON "using certificates from ${CERT_LOCATION}")
- ADD_DEFINITIONS(-DGIT_DEFAULT_CERT_LOCATION="${CERT_LOCATION}")
- ENDIF()
-
- SET(GIT_MBEDTLS 1)
- LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR})
- LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
- # mbedTLS has no pkgconfig file, hence we can't require it
- # https://github.com/ARMmbed/mbedtls/issues/228
- # For now, pass its link flags as our own
- LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
- ELSEIF (HTTPS_BACKEND STREQUAL "WinHTTP")
- # WinHTTP setup was handled in the WinHTTP-specific block above
+ IF(HAVE_REGCOMP_L)
+ SET(REGEX_BACKEND "regcomp_l")
+ ELSEIF(PCRE_FOUND)
+ SET(REGEX_BACKEND "pcre")
ELSE()
- MESSAGE(FATAL_ERROR "Asked for backend ${HTTPS_BACKEND} but it wasn't found")
+ SET(REGEX_BACKEND "builtin")
ENDIF()
-
- ADD_FEATURE_INFO(HTTPS ON "using ${HTTPS_BACKEND}")
- SET(GIT_HTTPS 1)
-ELSE()
- ADD_FEATURE_INFO(HTTPS OFF "no support")
ENDIF()
-# Specify sha1 implementation
-IF(SHA1_BACKEND STREQUAL "OpenSSL")
- IF(NOT OPENSSL_FOUND)
- FIND_PACKAGE(OpenSSL)
- IF(NOT OPENSSL_FOUND)
- MESSAGE(FATAL_ERROR "Requested OpenSSL SHA1 backend, but OpenSSL could not be found")
- ENDIF()
- ENDIF()
+IF(REGEX_BACKEND STREQUAL "regcomp_l")
+ ADD_FEATURE_INFO(regex ON "using system regcomp_l")
+ SET(GIT_REGEX_REGCOMP_L 1)
+ELSEIF(REGEX_BACKEND STREQUAL "pcre2")
+ FIND_PACKAGE(PCRE2)
- ADD_FEATURE_INFO(SHA ON "using OpenSSL")
- SET(GIT_SHA1_OPENSSL 1)
- IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- LIST(APPEND LIBGIT2_PC_LIBS "-lssl")
- ELSE()
- LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
+ IF(NOT PCRE2_FOUND)
+ MESSAGE(FATAL_ERROR "PCRE2 support was requested but not found")
ENDIF()
-ELSEIF(SHA1_BACKEND STREQUAL "CollisionDetection")
- ADD_FEATURE_INFO(SHA ON "using CollisionDetection")
- SET(GIT_SHA1_COLLISIONDETECT 1)
- ADD_DEFINITIONS(-DSHA1DC_NO_STANDARD_INCLUDES=1)
- ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_SHA1_C=\"common.h\")
- ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"common.h\")
- FILE(GLOB SRC_SHA1 hash/hash_collisiondetect.c hash/sha1dc/*)
-ELSEIF(SHA1_BACKEND STREQUAL "Generic")
- ADD_FEATURE_INFO(SHA ON "using Generic")
- FILE(GLOB SRC_SHA1 hash/hash_generic.c)
-ELSEIF(SHA1_BACKEND STREQUAL "Win32")
- ADD_FEATURE_INFO(SHA ON "using Win32")
- SET(GIT_SHA1_WIN32 1)
- FILE(GLOB SRC_SHA1 hash/hash_win32.c)
-ELSEIF(SHA1_BACKEND STREQUAL "CommonCrypto")
- ADD_FEATURE_INFO(SHA ON "using CommonCrypto")
- SET(GIT_SHA1_COMMON_CRYPTO 1)
-ELSEIF (SHA1_BACKEND STREQUAL "mbedTLS")
- ADD_FEATURE_INFO(SHA ON "using mbedTLS")
- SET(GIT_SHA1_MBEDTLS 1)
- FILE(GLOB SRC_SHA1 hash/hash_mbedtls.c)
- LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR})
- LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
- # mbedTLS has no pkgconfig file, hence we can't require it
- # https://github.com/ARMmbed/mbedtls/issues/228
- # For now, pass its link flags as our own
- LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
+
+ ADD_FEATURE_INFO(regex ON "using system PCRE2")
+ SET(GIT_REGEX_PCRE2 1)
+
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE2_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${PCRE2_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_REQUIRES "libpcre2-8")
+ELSEIF(REGEX_BACKEND STREQUAL "pcre")
+ ADD_FEATURE_INFO(regex ON "using system PCRE")
+ SET(GIT_REGEX_PCRE 1)
+
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${PCRE_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${PCRE_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_REQUIRES "libpcre")
+ELSEIF(REGEX_BACKEND STREQUAL "regcomp")
+ ADD_FEATURE_INFO(regex ON "using system regcomp")
+ SET(GIT_REGEX_REGCOMP 1)
+ELSEIF(REGEX_BACKEND STREQUAL "builtin")
+ ADD_FEATURE_INFO(regex ON "using bundled PCRE")
+ SET(GIT_REGEX_BUILTIN 1)
+
+ ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/pcre" "${libgit2_BINARY_DIR}/deps/pcre")
+ LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/pcre")
+ LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:pcre>)
ELSE()
- MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend ${SHA1_BACKEND}")
+ MESSAGE(FATAL_ERROR "The REGEX_BACKEND option provided is not supported")
ENDIF()
# Optional external dependency: http-parser
-FIND_PACKAGE(HTTP_Parser)
-IF (USE_EXT_HTTP_PARSER AND HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
- LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS})
- LIST(APPEND LIBGIT2_LIBS ${HTTP_PARSER_LIBRARIES})
- LIST(APPEND LIBGIT2_PC_LIBS "-lhttp_parser")
- ADD_FEATURE_INFO(http-parser ON "http-parser support")
+IF(USE_HTTP_PARSER STREQUAL "system")
+ FIND_PACKAGE(HTTP_Parser)
+
+ IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
+ LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS})
+ LIST(APPEND LIBGIT2_LIBS ${HTTP_PARSER_LIBRARIES})
+ LIST(APPEND LIBGIT2_PC_LIBS "-lhttp_parser")
+ ADD_FEATURE_INFO(http-parser ON "http-parser support (system)")
+ ELSE()
+ MESSAGE(FATAL_ERROR "http-parser support was requested but not found")
+ ENDIF()
ELSE()
MESSAGE(STATUS "http-parser version 2 was not found or disabled; using bundled 3rd-party sources.")
ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/http-parser" "${libgit2_BINARY_DIR}/deps/http-parser")
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${ZLIB_INCLUDE_DIRS})
LIST(APPEND LIBGIT2_LIBS ${ZLIB_LIBRARIES})
IF(APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- LIST(APPEND LIBGIT2_LIBS "z")
LIST(APPEND LIBGIT2_PC_LIBS "-lz")
ELSE()
LIST(APPEND LIBGIT2_PC_REQUIRES "zlib")
ENDIF()
ADD_FEATURE_INFO(SSH GIT_SSH "SSH transport support")
-# Optional external dependency: libgssapi
-IF (USE_GSSAPI)
- FIND_PACKAGE(GSSAPI)
+# Optional external dependency: ntlmclient
+IF (USE_NTLMCLIENT)
+ SET(GIT_NTLM 1)
+ ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/ntlmclient" "${libgit2_BINARY_DIR}/deps/ntlmclient")
+ LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/ntlmclient")
+ LIST(APPEND LIBGIT2_OBJECTS "$<TARGET_OBJECTS:ntlmclient>")
ENDIF()
-IF (GSSAPI_FOUND)
- SET(GIT_GSSAPI 1)
- LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES})
-ENDIF()
-ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support")
+ADD_FEATURE_INFO(ntlmclient GIT_NTLM "NTLM authentication support for Unix")
+
+# Optional external dependency: GSSAPI
+
+INCLUDE(SelectGSSAPI)
# Optional external dependency: iconv
IF (USE_ICONV)
SET(GIT_USE_STAT_MTIME_NSEC 1)
ENDIF()
-ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
+target_compile_definitions(git2internal PRIVATE _FILE_OFFSET_BITS=64)
# Collect sourcefiles
-FILE(GLOB SRC_H
+file(GLOB SRC_H
"${libgit2_SOURCE_DIR}/include/git2.h"
"${libgit2_SOURCE_DIR}/include/git2/*.h"
"${libgit2_SOURCE_DIR}/include/git2/sys/*.h")
+list(SORT SRC_H)
+target_sources(git2internal PRIVATE ${SRC_H})
# On Windows use specific platform sources
-IF (WIN32 AND NOT CYGWIN)
- ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0600)
-
- IF(MSVC)
- SET(WIN_RC "win32/git2.rc")
- ENDIF()
-
- FILE(GLOB SRC_OS win32/*.c win32/*.h)
-ELSEIF (AMIGA)
- ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R -DNO_MMAP)
-ELSE()
- IF (VALGRIND)
- ADD_DEFINITIONS(-DNO_MMAP)
- ENDIF()
- FILE(GLOB SRC_OS unix/*.c unix/*.h)
+if(WIN32 AND NOT CYGWIN)
+ SET(WIN_RC "win32/git2.rc")
+
+ file(GLOB SRC_OS win32/*.c win32/*.h)
+ list(SORT SRC_OS)
+ target_sources(git2internal PRIVATE ${SRC_OS})
+elseif(AMIGA)
+ target_compile_definitions(git2internal PRIVATE NO_ADDRINFO NO_READDIR_R NO_MMAP)
+else()
+ file(GLOB SRC_OS unix/*.c unix/*.h)
+ list(SORT SRC_OS)
+ target_sources(git2internal PRIVATE ${SRC_OS})
+endif()
+
+IF (USE_LEAK_CHECKER STREQUAL "valgrind")
+ target_compile_definitions(git2internal PRIVATE VALGRIND)
ENDIF()
-FILE(GLOB SRC_GIT2 *.c *.h
+
+file(GLOB SRC_GIT2 *.c *.h
+ allocators/*.c allocators/*.h
streams/*.c streams/*.h
transports/*.c transports/*.h
xdiff/*.c xdiff/*.h)
+list(SORT SRC_GIT2)
+target_sources(git2internal PRIVATE ${SRC_GIT2})
+
+IF(APPLE)
+ # The old Secure Transport API has been deprecated in macOS 10.15.
+ SET_SOURCE_FILES_PROPERTIES(streams/stransport.c PROPERTIES COMPILE_FLAGS -Wno-deprecated)
+ENDIF()
+
+# the xdiff dependency is not (yet) warning-free, disable warnings as
+# errors for the xdiff sources until we've sorted them out
+IF(MSVC)
+ SET_SOURCE_FILES_PROPERTIES(xdiff/xdiffi.c PROPERTIES COMPILE_FLAGS -WX-)
+ SET_SOURCE_FILES_PROPERTIES(xdiff/xutils.c PROPERTIES COMPILE_FLAGS -WX-)
+ENDIF()
# Determine architecture of the machine
IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
CONFIGURE_FILE(features.h.in git2/sys/features.h)
-SET(LIBGIT2_SOURCES ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_SSH} ${SRC_SHA1})
-
-ADD_LIBRARY(git2internal OBJECT ${LIBGIT2_SOURCES})
-SET_TARGET_PROPERTIES(git2internal PROPERTIES C_STANDARD 90)
IDE_SPLIT_SOURCES(git2internal)
LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:git2internal>)
-IF (${CMAKE_VERSION} VERSION_LESS 2.8.12)
- INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
- INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES})
-ELSE()
- TARGET_INCLUDE_DIRECTORIES(git2internal
- PRIVATE ${LIBGIT2_INCLUDES}
- PUBLIC ${libgit2_SOURCE_DIR}/include)
- TARGET_INCLUDE_DIRECTORIES(git2internal
- SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES})
-ENDIF()
+TARGET_INCLUDE_DIRECTORIES(git2internal PRIVATE ${LIBGIT2_INCLUDES} PUBLIC ${libgit2_SOURCE_DIR}/include)
+TARGET_INCLUDE_DIRECTORIES(git2internal SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES})
SET(LIBGIT2_OBJECTS ${LIBGIT2_OBJECTS} PARENT_SCOPE)
SET(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)
IDE_SPLIT_SOURCES(git2)
-IF (SONAME)
- SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
- SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_SOVERSION})
- IF (LIBGIT2_FILENAME)
- ADD_DEFINITIONS(-DLIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
- SET_TARGET_PROPERTIES(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME})
- ELSEIF (DEFINED LIBGIT2_PREFIX)
- SET_TARGET_PROPERTIES(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}")
- ENDIF()
-ENDIF()
-
-LIST(REMOVE_DUPLICATES LIBGIT2_PC_REQUIRES)
-STRING(REPLACE ";" " " LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES}")
-STRING(REPLACE ";" " " LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS}")
-CONFIGURE_FILE(${libgit2_SOURCE_DIR}/libgit2.pc.in ${libgit2_BINARY_DIR}/libgit2.pc @ONLY)
+if(SONAME)
+ set_target_properties(git2 PROPERTIES VERSION ${libgit2_VERSION})
+ set_target_properties(git2 PROPERTIES SOVERSION "${libgit2_VERSION_MAJOR}.${libgit2_VERSION_MINOR}")
+ if(LIBGIT2_FILENAME)
+ target_compile_definitions(git2internal PRIVATE LIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\")
+ set_target_properties(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME})
+ elseif(DEFINED LIBGIT2_PREFIX)
+ set_target_properties(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}")
+ endif()
+endif()
+
+PKG_BUILD_CONFIG(NAME libgit2
+ VERSION ${libgit2_VERSION}
+ DESCRIPTION "The git library, take 2"
+ LIBS_SELF git2
+ PRIVATE_LIBS ${LIBGIT2_PC_LIBS}
+ REQUIRES ${LIBGIT2_PC_REQUIRES}
+)
IF (MSVC_IDE)
# Precompiled headers
# Install
INSTALL(TARGETS git2
- RUNTIME DESTINATION ${BIN_INSTALL_DIR}
- LIBRARY DESTINATION ${LIB_INSTALL_DIR}
- ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
-INSTALL(FILES ${libgit2_BINARY_DIR}/libgit2.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig )
-INSTALL(DIRECTORY ${libgit2_SOURCE_DIR}/include/git2 DESTINATION ${INCLUDE_INSTALL_DIR} )
-INSTALL(FILES ${libgit2_SOURCE_DIR}/include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} )
+INSTALL(DIRECTORY ${libgit2_SOURCE_DIR}/include/git2 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+INSTALL(FILES ${libgit2_SOURCE_DIR}/include/git2.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
#include "alloc.h"
-#if defined(GIT_MSVC_CRTDBG)
-# include "win32/w32_crtdbg_stacktrace.h"
-#else
-# include "stdalloc.h"
-#endif
+#include "allocators/stdalloc.h"
+#include "allocators/win32_crtdbg.h"
git_allocator git__allocator;
memcpy(&git__allocator, allocator, sizeof(*allocator));
return 0;
}
-
-#if !defined(GIT_MSVC_CRTDBG)
-int git_win32_crtdbg_init_allocator(git_allocator *allocator)
-{
- GIT_UNUSED(allocator);
- git_error_set(GIT_EINVALID, "crtdbg memory allocator not available");
- return -1;
-}
-#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "stdalloc.h"
+
+static void *stdalloc__malloc(size_t len, const char *file, int line)
+{
+ void *ptr = malloc(len);
+
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+
+ if (!ptr) git_error_set_oom();
+ return ptr;
+}
+
+static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line)
+{
+ void *ptr = calloc(nelem, elsize);
+
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+
+ if (!ptr) git_error_set_oom();
+ return ptr;
+}
+
+static char *stdalloc__strdup(const char *str, const char *file, int line)
+{
+ char *ptr = strdup(str);
+
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+
+ if (!ptr) git_error_set_oom();
+ return ptr;
+}
+
+static char *stdalloc__strndup(const char *str, size_t n, const char *file, int line)
+{
+ size_t length = 0, alloclength;
+ char *ptr;
+
+ length = p_strnlen(str, n);
+
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
+ !(ptr = stdalloc__malloc(alloclength, file, line)))
+ return NULL;
+
+ if (length)
+ memcpy(ptr, str, length);
+
+ ptr[length] = '\0';
+
+ return ptr;
+}
+
+static char *stdalloc__substrdup(const char *start, size_t n, const char *file, int line)
+{
+ char *ptr;
+ size_t alloclen;
+
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
+ !(ptr = stdalloc__malloc(alloclen, file, line)))
+ return NULL;
+
+ memcpy(ptr, start, n);
+ ptr[n] = '\0';
+ return ptr;
+}
+
+static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line)
+{
+ void *new_ptr = realloc(ptr, size);
+
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+
+ if (!new_ptr) git_error_set_oom();
+ return new_ptr;
+}
+
+static void *stdalloc__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
+{
+ size_t newsize;
+
+ if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
+ return NULL;
+
+ return stdalloc__realloc(ptr, newsize, file, line);
+}
+
+static void *stdalloc__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
+{
+ return stdalloc__reallocarray(NULL, nelem, elsize, file, line);
+}
+
+static void stdalloc__free(void *ptr)
+{
+ free(ptr);
+}
+
+int git_stdalloc_init_allocator(git_allocator *allocator)
+{
+ allocator->gmalloc = stdalloc__malloc;
+ allocator->gcalloc = stdalloc__calloc;
+ allocator->gstrdup = stdalloc__strdup;
+ allocator->gstrndup = stdalloc__strndup;
+ allocator->gsubstrdup = stdalloc__substrdup;
+ allocator->grealloc = stdalloc__realloc;
+ allocator->greallocarray = stdalloc__reallocarray;
+ allocator->gmallocarray = stdalloc__mallocarray;
+ allocator->gfree = stdalloc__free;
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_allocators_stdalloc_h__
+#define INCLUDE_allocators_stdalloc_h__
+
+#include "common.h"
+
+#include "alloc.h"
+
+int git_stdalloc_init_allocator(git_allocator *allocator);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "win32_crtdbg.h"
+
+#if defined(GIT_MSVC_CRTDBG)
+
+#include "win32/w32_crtdbg_stacktrace.h"
+
+static void *crtdbg__malloc(size_t len, const char *file, int line)
+{
+ void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!ptr) git_error_set_oom();
+ return ptr;
+}
+
+static void *crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line)
+{
+ void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!ptr) git_error_set_oom();
+ return ptr;
+}
+
+static char *crtdbg__strdup(const char *str, const char *file, int line)
+{
+ char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!ptr) git_error_set_oom();
+ return ptr;
+}
+
+static char *crtdbg__strndup(const char *str, size_t n, const char *file, int line)
+{
+ size_t length = 0, alloclength;
+ char *ptr;
+
+ length = p_strnlen(str, n);
+
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
+ !(ptr = crtdbg__malloc(alloclength, file, line)))
+ return NULL;
+
+ if (length)
+ memcpy(ptr, str, length);
+
+ ptr[length] = '\0';
+
+ return ptr;
+}
+
+static char *crtdbg__substrdup(const char *start, size_t n, const char *file, int line)
+{
+ char *ptr;
+ size_t alloclen;
+
+ if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
+ !(ptr = crtdbg__malloc(alloclen, file, line)))
+ return NULL;
+
+ memcpy(ptr, start, n);
+ ptr[n] = '\0';
+ return ptr;
+}
+
+static void *crtdbg__realloc(void *ptr, size_t size, const char *file, int line)
+{
+ void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
+ if (!new_ptr) git_error_set_oom();
+ return new_ptr;
+}
+
+static void *crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
+{
+ size_t newsize;
+
+ if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
+ return NULL;
+
+ return crtdbg__realloc(ptr, newsize, file, line);
+}
+
+static void *crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
+{
+ return crtdbg__reallocarray(NULL, nelem, elsize, file, line);
+}
+
+static void crtdbg__free(void *ptr)
+{
+ free(ptr);
+}
+
+int git_win32_crtdbg_init_allocator(git_allocator *allocator)
+{
+ allocator->gmalloc = crtdbg__malloc;
+ allocator->gcalloc = crtdbg__calloc;
+ allocator->gstrdup = crtdbg__strdup;
+ allocator->gstrndup = crtdbg__strndup;
+ allocator->gsubstrdup = crtdbg__substrdup;
+ allocator->grealloc = crtdbg__realloc;
+ allocator->greallocarray = crtdbg__reallocarray;
+ allocator->gmallocarray = crtdbg__mallocarray;
+ allocator->gfree = crtdbg__free;
+ return 0;
+}
+
+#else
+
+int git_win32_crtdbg_init_allocator(git_allocator *allocator)
+{
+ GIT_UNUSED(allocator);
+ git_error_set(GIT_EINVALID, "crtdbg memory allocator not available");
+ return -1;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_allocators_crtdbg_h
+#define INCLUDE_allocators_crtdbg_h
+
+#include "common.h"
+
+#include "alloc.h"
+
+int git_win32_crtdbg_init_allocator(git_allocator *allocator);
+
+#endif
#include "apply.h"
-#include <assert.h>
-
#include "git2/apply.h"
#include "git2/patch.h"
#include "git2/filter.h"
#include "git2/repository.h"
#include "array.h"
#include "patch.h"
-#include "fileops.h"
+#include "futils.h"
#include "delta.h"
#include "zstream.h"
#include "reader.h"
#include "index.h"
-#define apply_err(...) \
- ( git_error_set(GIT_ERROR_PATCH, __VA_ARGS__), GIT_EAPPLYFAIL )
-
typedef struct {
/* The lines that we allocate ourself are allocated out of the pool.
* (Lines may have been allocated out of the diff.)
git_vector lines;
} patch_image;
+static int apply_err(const char *fmt, ...) GIT_FORMAT_PRINTF(1, 2);
+static int apply_err(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ git_error_vset(GIT_ERROR_PATCH, fmt, ap);
+ va_end(ap);
+
+ return GIT_EAPPLYFAIL;
+}
+
static void patch_line_init(
git_diff_line *out,
const char *in,
memset(out, 0x0, sizeof(patch_image));
- git_pool_init(&out->pool, sizeof(git_diff_line));
+ if (git_pool_init(&out->pool, sizeof(git_diff_line)) < 0)
+ return -1;
+
+ if (!in_len)
+ return 0;
for (start = in; start < in + in_len; start = end) {
- end = memchr(start, '\n', in_len);
+ end = memchr(start, '\n', in_len - (start - in));
if (end == NULL)
end = in + in_len;
for (i = 0; i < hunk->line_count; i++) {
size_t linenum = hunk->line_start + i;
- git_diff_line *line = git_array_get(patch->lines, linenum);
+ git_diff_line *line = git_array_get(patch->lines, linenum), *prev;
if (!line) {
error = apply_err("preimage does not contain line %"PRIuZ, linenum);
goto done;
}
- if (line->origin == GIT_DIFF_LINE_CONTEXT ||
- line->origin == GIT_DIFF_LINE_DELETION) {
- if ((error = git_vector_insert(&preimage.lines, line)) < 0)
- goto done;
- }
-
- if (line->origin == GIT_DIFF_LINE_CONTEXT ||
- line->origin == GIT_DIFF_LINE_ADDITION) {
- if ((error = git_vector_insert(&postimage.lines, line)) < 0)
- goto done;
+ switch (line->origin) {
+ case GIT_DIFF_LINE_CONTEXT_EOFNL:
+ case GIT_DIFF_LINE_DEL_EOFNL:
+ case GIT_DIFF_LINE_ADD_EOFNL:
+ prev = i ? git_array_get(patch->lines, linenum - 1) : NULL;
+ if (prev && prev->content[prev->content_len - 1] == '\n')
+ prev->content_len -= 1;
+ break;
+ case GIT_DIFF_LINE_CONTEXT:
+ if ((error = git_vector_insert(&preimage.lines, line)) < 0 ||
+ (error = git_vector_insert(&postimage.lines, line)) < 0)
+ goto done;
+ break;
+ case GIT_DIFF_LINE_DELETION:
+ if ((error = git_vector_insert(&preimage.lines, line)) < 0)
+ goto done;
+ break;
+ case GIT_DIFF_LINE_ADDITION:
+ if ((error = git_vector_insert(&postimage.lines, line)) < 0)
+ goto done;
+ break;
}
}
git_filemode_t pre_filemode;
git_index_entry pre_entry, post_entry;
bool skip_preimage = false;
- size_t pos;
int error;
if ((error = git_patch_from_diff(&patch, diff, i)) < 0)
*/
if (delta->status != GIT_DELTA_RENAMED &&
delta->status != GIT_DELTA_ADDED) {
- pos = git_strmap_lookup_index(removed_paths, delta->old_file.path);
- if (git_strmap_valid_index(removed_paths, pos)) {
+ if (git_strmap_exists(removed_paths, delta->old_file.path)) {
error = apply_err("path '%s' has been renamed or deleted", delta->old_file.path);
goto done;
}
if (delta->status != GIT_DELTA_DELETED) {
if ((error = git_apply__patch(&post_contents, &filename, &mode,
pre_contents.ptr, pre_contents.size, patch, opts)) < 0 ||
- (error = git_blob_create_frombuffer(&post_id, repo,
+ (error = git_blob_create_from_buffer(&post_id, repo,
post_contents.ptr, post_contents.size)) < 0)
goto done;
if (delta->status == GIT_DELTA_RENAMED ||
delta->status == GIT_DELTA_DELETED)
- git_strmap_insert(removed_paths, delta->old_file.path, (char *)delta->old_file.path, &error);
+ error = git_strmap_set(removed_paths, delta->old_file.path, (char *) delta->old_file.path);
if (delta->status == GIT_DELTA_RENAMED ||
delta->status == GIT_DELTA_ADDED)
size_t i;
int error = 0;
- if (git_strmap_alloc(&removed_paths) < 0)
+ if (git_strmap_new(&removed_paths) < 0)
return -1;
for (i = 0; i < git_diff_num_deltas(diff); i++) {
for (i = 0; i < git_diff_num_deltas(diff); i++) {
delta = git_diff_get_delta(diff, i);
- if ((error = git_index_remove(postimage,
- delta->old_file.path, 0)) < 0)
- goto done;
+ if (delta->status == GIT_DELTA_DELETED ||
+ delta->status == GIT_DELTA_RENAMED) {
+ if ((error = git_index_remove(postimage,
+ delta->old_file.path, 0)) < 0)
+ goto done;
+ }
}
if ((error = apply_deltas(repo, pre_reader, NULL, post_reader, postimage, diff, &opts)) < 0)
return error;
}
+int git_apply_options_init(git_apply_options *opts, unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+ opts, version, git_apply_options, GIT_APPLY_OPTIONS_INIT);
+ return 0;
+}
+
/*
* Handle the three application options ("locations"):
*
(error = git_reader_for_index(&post_reader, repo, postimage)) < 0)
goto done;
- if ((error = git_repository_index(&index, repo)) < 0 ||
- (error = git_indexwriter_init(&indexwriter, index)) < 0)
- goto done;
+ if (!(opts.flags & GIT_APPLY_CHECK))
+ if ((error = git_repository_index(&index, repo)) < 0 ||
+ (error = git_indexwriter_init(&indexwriter, index)) < 0)
+ goto done;
if ((error = apply_deltas(repo, pre_reader, preimage, post_reader, postimage, diff, &opts)) < 0)
goto done;
+ if ((opts.flags & GIT_APPLY_CHECK))
+ goto done;
+
switch (location) {
case GIT_APPLY_LOCATION_BOTH:
error = git_apply__to_workdir(repo, diff, preimage, postimage, location, &opts);
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_assert_safe_h__
+#define INCLUDE_assert_safe_h__
+
+/*
+ * In a debug build, we'll assert(3) for aide in debugging. In release
+ * builds, we will provide macros that will set an error message that
+ * indicate a failure and return. Note that memory leaks can occur in
+ * a release-mode assertion failure -- it is impractical to provide
+ * safe clean up routines in these very extreme failures, but care
+ * should be taken to not leak very large objects.
+ */
+
+#if (defined(_DEBUG) || defined(GIT_ASSERT_HARD)) && GIT_ASSERT_HARD != 0
+# include <assert.h>
+
+# define GIT_ASSERT(expr) assert(expr)
+# define GIT_ASSERT_ARG(expr) assert(expr)
+
+# define GIT_ASSERT_WITH_RETVAL(expr, fail) assert(expr)
+# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) assert(expr)
+#else
+
+/** Internal consistency check to stop the function. */
+# define GIT_ASSERT(expr) GIT_ASSERT_WITH_RETVAL(expr, -1)
+
+/**
+ * Assert that a consumer-provided argument is valid, setting an
+ * actionable error message and returning -1 if it is not.
+ */
+# define GIT_ASSERT_ARG(expr) GIT_ASSERT_ARG_WITH_RETVAL(expr, -1)
+
+/** Internal consistency check to return the `fail` param on failure. */
+# define GIT_ASSERT_WITH_RETVAL(expr, fail) \
+ GIT_ASSERT__WITH_RETVAL(expr, GIT_ERROR_INTERNAL, "unrecoverable internal error", fail)
+
+/**
+ * Assert that a consumer-provided argument is valid, setting an
+ * actionable error message and returning the `fail` param if not.
+ */
+# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) \
+ GIT_ASSERT__WITH_RETVAL(expr, GIT_ERROR_INVALID, "invalid argument", fail)
+
+# define GIT_ASSERT__WITH_RETVAL(expr, code, msg, fail) do { \
+ if (!(expr)) { \
+ git_error_set(code, "%s: '%s'", msg, #expr); \
+ return fail; \
+ } \
+ } while(0)
+
+#endif /* GIT_ASSERT_HARD */
+
+#endif
const char *git_attr__false = "[internal]__FALSE__";
const char *git_attr__unset = "[internal]__UNSET__";
-git_attr_t git_attr_value(const char *attr)
+git_attr_value_t git_attr_value(const char *attr)
{
if (attr == NULL || attr == git_attr__unset)
- return GIT_ATTR_UNSPECIFIED_T;
+ return GIT_ATTR_VALUE_UNSPECIFIED;
if (attr == git_attr__true)
- return GIT_ATTR_TRUE_T;
+ return GIT_ATTR_VALUE_TRUE;
if (attr == git_attr__false)
- return GIT_ATTR_FALSE_T;
+ return GIT_ATTR_VALUE_FALSE;
- return GIT_ATTR_VALUE_T;
+ return GIT_ATTR_VALUE_STRING;
}
static int collect_attr_files(
return -1;
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
- (error = git_strmap_alloc(&seen)) < 0)
+ (error = git_strmap_new(&seen)) < 0)
goto cleanup;
git_vector_foreach(&files, i, file) {
if (git_strmap_exists(seen, assign->name))
continue;
- git_strmap_insert(seen, assign->name, assign, &error);
- if (error < 0)
+ if ((error = git_strmap_set(seen, assign->name, assign)) < 0)
goto cleanup;
error = callback(assign->name, assign->value, payload);
git_attr_session *attr_session,
git_attr_file_source source,
const char *base,
- const char *file)
+ const char *file,
+ bool allow_macros)
{
int error;
git_attr_file *preload = NULL;
if (!file)
return 0;
- if (!(error = git_attr_cache__get(
- &preload, repo, attr_session, source, base, file, git_attr_file__parse_buffer)))
+ if (!(error = git_attr_cache__get(&preload, repo, attr_session, source, base, file,
+ git_attr_file__parse_buffer, allow_macros)))
git_attr_file__free(preload);
return error;
return 0;
}
-static int attr_setup(git_repository *repo, git_attr_session *attr_session)
+static int attr_setup(
+ git_repository *repo,
+ git_attr_session *attr_session,
+ uint32_t flags)
{
- int error = 0;
- const char *workdir = git_repository_workdir(repo);
- git_index *idx = NULL;
git_buf path = GIT_BUF_INIT;
+ git_index *idx = NULL;
+ const char *workdir;
+ int error = 0;
if (attr_session && attr_session->init_setup)
return 0;
if ((error = git_attr_cache__init(repo)) < 0)
return error;
- /* preload attribute files that could contain macros so the
- * definitions will be available for later file parsing
+ /*
+ * Preload attribute files that could contain macros so the
+ * definitions will be available for later file parsing.
*/
- error = system_attr_file(&path, attr_session);
-
- if (error == 0)
- error = preload_attr_file(
- repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, path.ptr);
-
- if (error != GIT_ENOTFOUND)
- goto out;
-
- if ((error = preload_attr_file(
- repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
- NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
- goto out;
+ if ((error = system_attr_file(&path, attr_session)) < 0 ||
+ (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
+ NULL, path.ptr, true)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto out;
+ }
- if ((error = git_repository_item_path(&path,
- repo, GIT_REPOSITORY_ITEM_INFO)) < 0)
+ if ((error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
+ NULL, git_repository_attr_cache(repo)->cfg_attr_file, true)) < 0)
goto out;
- if ((error = preload_attr_file(
- repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
- path.ptr, GIT_ATTR_FILE_INREPO)) < 0)
- goto out;
+ git_buf_clear(&path); /* git_repository_item_path expects an empty buffer, because it uses git_buf_set */
+ if ((error = git_repository_item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
+ (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
+ path.ptr, GIT_ATTR_FILE_INREPO, true)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto out;
+ }
- if (workdir != NULL &&
- (error = preload_attr_file(
- repo, attr_session, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
- goto out;
+ if ((workdir = git_repository_workdir(repo)) != NULL &&
+ (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
+ workdir, GIT_ATTR_FILE, true)) < 0)
+ goto out;
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
- (error = preload_attr_file(
- repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
+ (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_INDEX,
+ NULL, GIT_ATTR_FILE, true)) < 0)
+ goto out;
+
+ if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 &&
+ (error = preload_attr_file(repo, attr_session, GIT_ATTR_FILE__FROM_HEAD,
+ NULL, GIT_ATTR_FILE, true)) < 0)
goto out;
if (attr_session)
break;
}
+ if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0)
+ srcs[count++] = GIT_ATTR_FILE__FROM_HEAD;
+
return count;
}
git_vector *list,
git_attr_file_source source,
const char *base,
- const char *filename)
+ const char *filename,
+ bool allow_macros)
{
int error = 0;
git_attr_file *file = NULL;
error = git_attr_cache__get(&file, repo, attr_session,
- source, base, filename, git_attr_file__parse_buffer);
+ source, base, filename, git_attr_file__parse_buffer, allow_macros);
if (error < 0)
return error;
static int push_one_attr(void *ref, const char *path)
{
- int error = 0, n_src, i;
attr_walk_up_info *info = (attr_walk_up_info *)ref;
- git_attr_file_source src[2];
+ git_attr_file_source src[GIT_ATTR_FILE_NUM_SOURCES];
+ int error = 0, n_src, i;
+ bool allow_macros;
n_src = attr_decide_sources(
info->flags, info->workdir != NULL, info->index != NULL, src);
+ allow_macros = info->workdir ? !strcmp(info->workdir, path) : false;
for (i = 0; !error && i < n_src; ++i)
- error = push_attr_file(info->repo, info->attr_session,
- info->files, src[i], path, GIT_ATTR_FILE);
+ error = push_attr_file(info->repo, info->attr_session, info->files,
+ src[i], path, GIT_ATTR_FILE, allow_macros);
return error;
}
const char *workdir = git_repository_workdir(repo);
attr_walk_up_info info = { NULL };
- if ((error = attr_setup(repo, attr_session)) < 0)
+ if ((error = attr_setup(repo, attr_session, flags)) < 0)
return error;
/* Resolve path in a non-bare repo */
* - $GIT_PREFIX/etc/gitattributes
*/
- error = git_repository_item_path(&attrfile, repo, GIT_REPOSITORY_ITEM_INFO);
- if (error < 0)
- goto cleanup;
-
- error = push_attr_file(
- repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
- attrfile.ptr, GIT_ATTR_FILE_INREPO);
- if (error < 0)
- goto cleanup;
+ if ((error = git_repository_item_path(&attrfile, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
+ (error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
+ attrfile.ptr, GIT_ATTR_FILE_INREPO, true)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto cleanup;
+ }
info.repo = repo;
info.attr_session = attr_session;
goto cleanup;
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
- error = push_attr_file(
- repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
- NULL, git_repository_attr_cache(repo)->cfg_attr_file);
+ error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
+ NULL, git_repository_attr_cache(repo)->cfg_attr_file, true);
if (error < 0)
goto cleanup;
}
error = system_attr_file(&dir, attr_session);
if (!error)
- error = push_attr_file(
- repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
- NULL, dir.ptr);
+ error = push_attr_file(repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
+ NULL, dir.ptr, true);
else if (error == GIT_ENOTFOUND)
error = 0;
}
#include "repository.h"
#include "filebuf.h"
#include "attrcache.h"
+#include "buf_text.h"
#include "git2/blob.h"
#include "git2/tree.h"
#include "blob.h"
#include "index.h"
+#include "wildmatch.h"
#include <ctype.h>
static void attr_file_free(git_attr_file *file)
if (git_mutex_init(&attrs->lock) < 0) {
git_error_set(GIT_ERROR_OS, "failed to initialize lock");
- git__free(attrs);
- return -1;
+ goto on_error;
}
- git_pool_init(&attrs->pool, 1);
+ if (git_pool_init(&attrs->pool, 1) < 0)
+ goto on_error;
+
GIT_REFCOUNT_INC(attrs);
attrs->entry = entry;
attrs->source = source;
*out = attrs;
return 0;
+
+on_error:
+ git__free(attrs);
+ return -1;
}
int git_attr_file__clear_rules(git_attr_file *file, bool need_lock)
git_attr_session *attr_session,
git_attr_file_entry *entry,
git_attr_file_source source,
- git_attr_file_parser parser)
+ git_attr_file_parser parser,
+ bool allow_macros)
{
int error = 0;
+ git_tree *tree = NULL;
+ git_tree_entry *tree_entry = NULL;
git_blob *blob = NULL;
git_buf content = GIT_BUF_INIT;
+ const char *content_str;
git_attr_file *file;
struct stat st;
bool nonexistent = false;
+ int bom_offset;
+ git_bom_t bom;
+ git_oid id;
+ git_object_size_t blobsize;
*out = NULL;
/* in-memory attribute file doesn't need data */
break;
case GIT_ATTR_FILE__FROM_INDEX: {
- git_oid id;
- git_off_t blobsize;
-
if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
(error = git_blob_lookup(&blob, repo, &id)) < 0)
return error;
break;
}
+ case GIT_ATTR_FILE__FROM_HEAD: {
+ if ((error = git_repository_head_tree(&tree, repo)) < 0 ||
+ (error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0 ||
+ (error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 0)
+ goto cleanup;
+
+ /*
+ * Do not assume that data straight from the ODB is NULL-terminated;
+ * copy the contents of a file to a buffer to work on.
+ */
+ blobsize = git_blob_rawsize(blob);
+
+ GIT_ERROR_CHECK_BLOBSIZE(blobsize);
+ if ((error = git_buf_put(&content,
+ git_blob_rawcontent(blob), (size_t)blobsize)) < 0)
+ goto cleanup;
+
+ break;
+ }
default:
git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source);
return -1;
if ((error = git_attr_file__new(&file, entry, source)) < 0)
goto cleanup;
+ /* advance over a UTF8 BOM */
+ content_str = git_buf_cstr(&content);
+ bom_offset = git_buf_text_detect_bom(&bom, &content);
+
+ if (bom == GIT_BOM_UTF8)
+ content_str += bom_offset;
+
/* store the key of the attr_reader; don't bother with cache
* invalidation during the same attr reader session.
*/
if (attr_session)
file->session_key = attr_session->key;
- if (parser && (error = parser(repo, file, git_buf_cstr(&content))) < 0) {
+ if (parser && (error = parser(repo, file, content_str, allow_macros)) < 0) {
git_attr_file__free(file);
goto cleanup;
}
file->nonexistent = 1;
else if (source == GIT_ATTR_FILE__FROM_INDEX)
git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
+ else if (source == GIT_ATTR_FILE__FROM_HEAD)
+ git_oid_cpy(&file->cache_data.oid, git_tree_id(tree));
else if (source == GIT_ATTR_FILE__FROM_FILE)
git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
/* else always cacheable */
cleanup:
git_blob_free(blob);
+ git_tree_entry_free(tree_entry);
+ git_tree_free(tree);
git_buf_dispose(&content);
return error;
return (git_oid__cmp(&file->cache_data.oid, &id) != 0);
}
+ case GIT_ATTR_FILE__FROM_HEAD: {
+ git_tree *tree;
+ int error;
+
+ if ((error = git_repository_head_tree(&tree, repo)) < 0)
+ return error;
+
+ error = git_oid__cmp(&file->cache_data.oid, git_tree_id(tree));
+
+ git_tree_free(tree);
+ return error;
+ }
+
default:
git_error_set(GIT_ERROR_INVALID, "invalid file type %d", file->source);
return -1;
const char *pattern);
int git_attr_file__parse_buffer(
- git_repository *repo, git_attr_file *attrs, const char *data)
+ git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros)
{
- int error = 0;
const char *scan = data, *context = NULL;
git_attr_rule *rule = NULL;
+ int error = 0;
- /* if subdir file path, convert context for file paths */
- if (attrs->entry &&
- git_path_root(attrs->entry->path) < 0 &&
- !git__suffixcmp(attrs->entry->path, "/" GIT_ATTR_FILE))
+ /* If subdir file path, convert context for file paths */
+ if (attrs->entry && git_path_root(attrs->entry->path) < 0 &&
+ !git__suffixcmp(attrs->entry->path, "/" GIT_ATTR_FILE))
context = attrs->entry->path;
if (git_mutex_lock(&attrs->lock) < 0) {
}
while (!error && *scan) {
- /* allocate rule if needed */
- if (!rule && !(rule = git__calloc(1, sizeof(*rule)))) {
- error = -1;
- break;
- }
-
- rule->match.flags =
- GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO;
-
- /* parse the next "pattern attr attr attr" line */
- if (!(error = git_attr_fnmatch__parse(
- &rule->match, &attrs->pool, context, &scan)) &&
- !(error = git_attr_assignment__parse(
- repo, &attrs->pool, &rule->assigns, &scan)))
+ /* Allocate rule if needed, otherwise re-use previous rule */
+ if (!rule) {
+ rule = git__calloc(1, sizeof(*rule));
+ GIT_ERROR_CHECK_ALLOC(rule);
+ } else
+ git_attr_rule__clear(rule);
+
+ rule->match.flags = GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO;
+
+ /* Parse the next "pattern attr attr attr" line */
+ if ((error = git_attr_fnmatch__parse(&rule->match, &attrs->pool, context, &scan)) < 0 ||
+ (error = git_attr_assignment__parse(repo, &attrs->pool, &rule->assigns, &scan)) < 0)
{
- if (rule->match.flags & GIT_ATTR_FNMATCH_MACRO)
- /* TODO: warning if macro found in file below repo root */
- error = git_attr_cache__insert_macro(repo, rule);
- else
- error = git_vector_insert(&attrs->rules, rule);
+ if (error != GIT_ENOTFOUND)
+ goto out;
+ error = 0;
+ continue;
}
- /* if the rule wasn't a pattern, on to the next */
- if (error < 0) {
- git_attr_rule__clear(rule); /* reset rule contents */
- if (error == GIT_ENOTFOUND)
- error = 0;
- } else {
- rule = NULL; /* vector now "owns" the rule */
- }
+ if (rule->match.flags & GIT_ATTR_FNMATCH_MACRO) {
+ /* TODO: warning if macro found in file below repo root */
+ if (!allow_macros)
+ continue;
+ if ((error = git_attr_cache__insert_macro(repo, rule)) < 0)
+ goto out;
+ } else if ((error = git_vector_insert(&attrs->rules, rule)) < 0)
+ goto out;
+
+ rule = NULL;
}
+out:
git_mutex_unlock(&attrs->lock);
git_attr_rule__free(rule);
int git_attr_file__load_standalone(git_attr_file **out, const char *path)
{
- int error;
- git_attr_file *file;
git_buf content = GIT_BUF_INIT;
+ git_attr_file *file = NULL;
+ int error;
- error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE);
- if (error < 0)
- return error;
+ if ((error = git_futils_readbuffer(&content, path)) < 0)
+ goto out;
- error = git_attr_cache__alloc_file_entry(
- &file->entry, NULL, path, &file->pool);
- if (error < 0) {
- git_attr_file__free(file);
- return error;
- }
- /* because the cache entry is allocated from the file's own pool, we
+ /*
+ * Because the cache entry is allocated from the file's own pool, we
* don't have to free it - freeing file+pool will free cache entry, too.
*/
- if (!(error = git_futils_readbuffer(&content, path))) {
- error = git_attr_file__parse_buffer(NULL, file, content.ptr);
- git_buf_dispose(&content);
- }
+ if ((error = git_attr_file__new(&file, NULL, GIT_ATTR_FILE__FROM_FILE)) < 0 ||
+ (error = git_attr_file__parse_buffer(NULL, file, content.ptr, true)) < 0 ||
+ (error = git_attr_cache__alloc_file_entry(&file->entry, NULL, path, &file->pool)) < 0)
+ goto out;
+ *out = file;
+out:
if (error < 0)
git_attr_file__free(file);
- else
- *out = file;
+ git_buf_dispose(&content);
return error;
}
}
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
- flags |= FNM_CASEFOLD;
- if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
- flags |= FNM_LEADING_DIR;
+ flags |= WM_CASEFOLD;
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) {
filename = relpath;
- flags |= FNM_PATHNAME;
+ flags |= WM_PATHNAME;
} else {
filename = path->basename;
-
- if (path->is_dir)
- flags |= FNM_LEADING_DIR;
}
if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) {
path->basename == relpath)
return false;
- flags |= FNM_LEADING_DIR;
-
/* fail match if this is a file with same name as ignored folder */
samename = (match->flags & GIT_ATTR_FNMATCH_ICASE) ?
!strcasecmp(match->pattern, relpath) :
if (samename)
return false;
- return (p_fnmatch(match->pattern, relpath, flags) != FNM_NOMATCH);
+ return (wildmatch(match->pattern, relpath, flags) == WM_MATCH);
}
- return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH);
+ return (wildmatch(match->pattern, filename, flags) == WM_MATCH);
}
bool git_attr_rule__match(
* "cat-file.c" but not "mozilla-sha1/sha1.c".
*/
+/*
+ * Determine the length of trailing spaces. Escaped spaces do not count as
+ * trailing whitespace.
+ */
+static size_t trailing_space_length(const char *p, size_t len)
+{
+ size_t n, i;
+ for (n = len; n; n--) {
+ if (p[n-1] != ' ' && p[n-1] != '\t')
+ break;
+
+ /*
+ * Count escape-characters before space. In case where it's an
+ * even number of escape characters, then the escape char itself
+ * is escaped and the whitespace is an unescaped whitespace.
+ * Otherwise, the last escape char is not escaped and the
+ * whitespace in an escaped whitespace.
+ */
+ i = n;
+ while (i > 1 && p[i-2] == '\\')
+ i--;
+ if ((n - i) % 2)
+ break;
+ }
+ return len - n;
+}
+
+static size_t unescape_spaces(char *str)
+{
+ char *scan, *pos = str;
+ bool escaped = false;
+
+ if (!str)
+ return 0;
+
+ for (scan = str; *scan; scan++) {
+ if (!escaped && *scan == '\\') {
+ escaped = true;
+ continue;
+ }
+
+ /* Only insert the escape character for escaped non-spaces */
+ if (escaped && !git__isspace(*scan))
+ *pos++ = '\\';
+
+ *pos++ = *scan;
+ escaped = false;
+ }
+
+ if (pos != scan)
+ *pos = '\0';
+
+ return (pos - str);
+}
+
/*
* This will return 0 if the spec was filled out,
* GIT_ENOTFOUND if the fnmatch does not require matching, or
{
const char *pattern, *scan;
int slash_count, allow_space;
+ bool escaped;
assert(spec && base && *base);
pattern = *base;
- while (git__isspace(*pattern)) pattern++;
- if (!*pattern || *pattern == '#') {
+ while (!allow_space && git__isspace(*pattern))
+ pattern++;
+
+ if (!*pattern || *pattern == '#' || *pattern == '\n' ||
+ (*pattern == '\r' && *(pattern + 1) == '\n')) {
*base = git__next_line(pattern);
return GIT_ENOTFOUND;
}
if (*pattern == '!' && (spec->flags & GIT_ATTR_FNMATCH_ALLOWNEG) != 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_NEGATIVE;
- if ((spec->flags & GIT_ATTR_FNMATCH_NOLEADINGDIR) == 0)
- spec->flags |= GIT_ATTR_FNMATCH_LEADINGDIR;
pattern++;
}
slash_count = 0;
+ escaped = false;
+ /* Scan until a non-escaped whitespace. */
for (scan = pattern; *scan != '\0'; ++scan) {
- /* scan until (non-escaped) white space */
- if (git__isspace(*scan) && *(scan - 1) != '\\') {
- if (!allow_space || (*scan != ' ' && *scan != '\t' && *scan != '\r'))
- break;
- }
+ char c = *scan;
- if (*scan == '/') {
+ if (c == '\\' && !escaped) {
+ escaped = true;
+ continue;
+ } else if (git__isspace(c) && !escaped) {
+ if (!allow_space || (c != ' ' && c != '\t' && c != '\r'))
+ break;
+ } else if (c == '/') {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_FULLPATH;
slash_count++;
- if (pattern == scan)
+
+ if (slash_count == 1 && pattern == scan)
pattern++;
- }
- /* remember if we see an unescaped wildcard in pattern */
- else if (git__iswildcard(*scan) &&
- (scan == pattern || (*(scan - 1) != '\\')))
+ } else if (git__iswildcard(c) && !escaped) {
+ /* remember if we see an unescaped wildcard in pattern */
spec->flags = spec->flags | GIT_ATTR_FNMATCH_HASWILD;
+ }
+
+ escaped = false;
}
*base = scan;
return GIT_ENOTFOUND;
/* Remove trailing spaces. */
- while (pattern[spec->length - 1] == ' ' || pattern[spec->length - 1] == '\t')
- if (--spec->length == 0)
- return GIT_ENOTFOUND;
+ spec->length -= trailing_space_length(pattern, spec->length);
+
+ if (spec->length == 0)
+ return GIT_ENOTFOUND;
if (pattern[spec->length - 1] == '/') {
spec->length--;
if (--slash_count <= 0)
spec->flags = spec->flags & ~GIT_ATTR_FNMATCH_FULLPATH;
}
- if ((spec->flags & GIT_ATTR_FNMATCH_NOLEADINGDIR) == 0 &&
- spec->length >= 2 &&
- pattern[spec->length - 1] == '*' &&
- pattern[spec->length - 2] == '/') {
- spec->length -= 2;
- spec->flags = spec->flags | GIT_ATTR_FNMATCH_LEADINGDIR;
- /* leave FULLPATH match on, however */
- }
if (context) {
char *slash = strrchr(context, '/');
*base = git__next_line(pattern);
return -1;
} else {
- /* strip '\' that might have be used for internal whitespace */
- spec->length = git__unescape(spec->pattern);
- /* TODO: convert remaining '\' into '/' for POSIX ??? */
+ /* strip '\' that might have been used for internal whitespace */
+ spec->length = unescape_spaces(spec->pattern);
}
return 0;
{
assert(repo);
+ memset(session, 0, sizeof(*session));
session->key = git_atomic_inc(&repo->attr_session_key);
return 0;
#include "vector.h"
#include "pool.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#define GIT_ATTR_FILE ".gitattributes"
#define GIT_ATTR_FILE_INREPO "attributes"
#define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8)
#define GIT_ATTR_FNMATCH_ALLOWNEG (1U << 9)
#define GIT_ATTR_FNMATCH_ALLOWMACRO (1U << 10)
-#define GIT_ATTR_FNMATCH_LEADINGDIR (1U << 11)
-#define GIT_ATTR_FNMATCH_NOLEADINGDIR (1U << 12)
#define GIT_ATTR_FNMATCH__INCOMING \
- (GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | \
- GIT_ATTR_FNMATCH_ALLOWMACRO | GIT_ATTR_FNMATCH_NOLEADINGDIR)
+ (GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
typedef enum {
GIT_ATTR_FILE__IN_MEMORY = 0,
GIT_ATTR_FILE__FROM_FILE = 1,
GIT_ATTR_FILE__FROM_INDEX = 2,
+ GIT_ATTR_FILE__FROM_HEAD = 3,
- GIT_ATTR_FILE_NUM_SOURCES = 3
+ GIT_ATTR_FILE_NUM_SOURCES = 4
} git_attr_file_source;
extern const char *git_attr__true;
typedef int (*git_attr_file_parser)(
git_repository *repo,
git_attr_file *file,
- const char *data);
+ const char *data,
+ bool allow_macros);
/*
* git_attr_file API
git_attr_session *attr_session,
git_attr_file_entry *ce,
git_attr_file_source source,
- git_attr_file_parser parser);
+ git_attr_file_parser parser,
+ bool allow_macros);
int git_attr_file__load_standalone(
git_attr_file **out, const char *path);
git_repository *repo, git_attr_session *session, git_attr_file *file);
int git_attr_file__parse_buffer(
- git_repository *repo, git_attr_file *attrs, const char *data);
+ git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros);
int git_attr_file__clear_rules(
git_attr_file *file, bool need_lock);
GIT_INLINE(git_attr_file_entry *) attr_cache_lookup_entry(
git_attr_cache *cache, const char *path)
{
- size_t pos = git_strmap_lookup_index(cache->files, path);
-
- if (git_strmap_valid_index(cache->files, pos))
- return git_strmap_value_at(cache->files, pos);
- else
- return NULL;
+ return git_strmap_get(cache->files, path);
}
int git_attr_cache__alloc_file_entry(
cachesize++;
}
- ce = git_pool_mallocz(pool, (uint32_t)cachesize);
+ ce = git_pool_mallocz(pool, cachesize);
GIT_ERROR_CHECK_ALLOC(ce);
if (baselen) {
static int attr_cache_make_entry(
git_attr_file_entry **out, git_repository *repo, const char *path)
{
- int error = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
git_attr_file_entry *entry = NULL;
+ int error;
- error = git_attr_cache__alloc_file_entry(
- &entry, git_repository_workdir(repo), path, &cache->pool);
+ if ((error = git_attr_cache__alloc_file_entry(&entry, git_repository_workdir(repo),
+ path, &cache->pool)) < 0)
+ return error;
- if (!error) {
- git_strmap_insert(cache->files, entry->path, entry, &error);
- if (error > 0)
- error = 0;
- }
+ if ((error = git_strmap_set(cache->files, entry->path, entry)) < 0)
+ return error;
*out = entry;
return error;
git_attr_file_source source,
const char *base,
const char *filename,
- git_attr_file_parser parser)
+ git_attr_file_parser parser,
+ bool allow_macros)
{
int error = 0;
git_attr_cache *cache = git_repository_attr_cache(repo);
/* load file if we don't have one or if existing one is out of date */
if (!file || (error = git_attr_file__out_of_date(repo, attr_session, file)) > 0)
- error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser);
+ error = git_attr_file__load(&updated, repo, attr_session, entry, source, parser, allow_macros);
/* if we loaded the file, insert into and/or update cache */
if (updated) {
const char *filename)
{
git_attr_cache *cache = git_repository_attr_cache(repo);
- git_strmap *files;
- size_t pos;
git_attr_file_entry *entry;
+ git_strmap *files;
if (!cache || !(files = cache->files))
return false;
- pos = git_strmap_lookup_index(files, filename);
- if (!git_strmap_valid_index(files, pos))
+ if ((entry = git_strmap_get(files, filename)) == NULL)
return false;
- entry = git_strmap_value_at(files, pos);
-
return entry && (entry->file[source] != NULL);
}
/* allocate hashtable for attribute and ignore file contents,
* hashtable for attribute macros, and string pool
*/
- if ((ret = git_strmap_alloc(&cache->files)) < 0 ||
- (ret = git_strmap_alloc(&cache->macros)) < 0)
+ if ((ret = git_strmap_new(&cache->files)) < 0 ||
+ (ret = git_strmap_new(&cache->macros)) < 0 ||
+ (ret = git_pool_init(&cache->pool, 1)) < 0)
goto cancel;
- git_pool_init(&cache->pool, 1);
-
cache = git__compare_and_swap(&repo->attrcache, NULL, cache);
if (cache)
goto cancel; /* raced with another thread, free this but no error */
git_config_free(cfg);
/* insert default macros */
- return git_attr_add_macro(repo, "binary", "-diff -crlf -text");
+ return git_attr_add_macro(repo, "binary", "-diff -merge -text -crlf");
cancel:
attr_cache__free(cache);
return ret;
}
-void git_attr_cache_flush(git_repository *repo)
+int git_attr_cache_flush(git_repository *repo)
{
git_attr_cache *cache;
*/
if (repo && (cache = git__swap(repo->attrcache, NULL)) != NULL)
attr_cache__free(cache);
+
+ return 0;
}
int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
{
git_attr_cache *cache = git_repository_attr_cache(repo);
- git_strmap *macros = cache->macros;
- int error;
-
- /* TODO: generate warning log if (macro->assigns.length == 0) */
- if (macro->assigns.length == 0)
- return 0;
+ git_attr_rule *preexisting;
+ bool locked = false;
+ int error = 0;
- if (attr_cache_lock(cache) < 0) {
- git_error_set(GIT_ERROR_OS, "unable to get attr cache lock");
- error = -1;
- } else {
- git_strmap_insert(macros, macro->match.pattern, macro, &error);
- git_mutex_unlock(&cache->lock);
+ /*
+ * Callers assume that if we return success, that the
+ * macro will have been adopted by the attributes cache.
+ * Thus, we have to free the macro here if it's not being
+ * added to the cache.
+ *
+ * TODO: generate warning log if (macro->assigns.length == 0)
+ */
+ if (macro->assigns.length == 0) {
+ git_attr_rule__free(macro);
+ goto out;
}
- return (error < 0) ? -1 : 0;
+ if ((error = attr_cache_lock(cache)) < 0)
+ goto out;
+ locked = true;
+
+ if ((preexisting = git_strmap_get(cache->macros, macro->match.pattern)) != NULL)
+ git_attr_rule__free(preexisting);
+
+ if ((error = git_strmap_set(cache->macros, macro->match.pattern, macro)) < 0)
+ goto out;
+
+out:
+ if (locked)
+ attr_cache_unlock(cache);
+ return error;
}
git_attr_rule *git_attr_cache__lookup_macro(
git_repository *repo, const char *name)
{
git_strmap *macros = git_repository_attr_cache(repo)->macros;
- size_t pos;
- pos = git_strmap_lookup_index(macros, name);
-
- if (!git_strmap_valid_index(macros, pos))
- return NULL;
-
- return (git_attr_rule *)git_strmap_value_at(macros, pos);
+ return git_strmap_get(macros, name);
}
-
git_attr_file_source source,
const char *base,
const char *filename,
- git_attr_file_parser parser);
+ git_attr_file_parser parser,
+ bool allow_macros);
extern bool git_attr_cache__is_cached(
git_repository *repo,
memcpy(out, in, sizeof(git_blame_options));
/* No newest_commit => HEAD */
- if (git_oid_iszero(&out->newest_commit)) {
+ if (git_oid_is_zero(&out->newest_commit)) {
if (git_reference_name_to_id(&out->newest_commit, repo, "HEAD") < 0) {
return -1;
}
static int index_blob_lines(git_blame *blame)
{
const char *buf = blame->final_buf;
- git_off_t len = blame->final_buf_size;
+ size_t len = blame->final_buf_size;
int num = 0, incomplete = 0, bol = 1;
size_t *i;
if ((error = load_blob(blame)) < 0 ||
(error = git_blame__get_origin(&o, blame, blame->final, blame->path)) < 0)
goto cleanup;
+
+ if (git_blob_rawsize(blame->final_blob) > SIZE_MAX) {
+ git_error_set(GIT_ERROR_NOMEMORY, "blob is too large to blame");
+ error = -1;
+ goto cleanup;
+ }
+
blame->final_buf = git_blob_rawcontent(blame->final_blob);
- blame->final_buf_size = git_blob_rawsize(blame->final_blob);
+ blame->final_buf_size = (size_t)git_blob_rawsize(blame->final_blob);
ent = git__calloc(1, sizeof(git_blame__entry));
GIT_ERROR_CHECK_ALLOC(ent);
static bool hunk_is_bufferblame(git_blame_hunk *hunk)
{
- return git_oid_iszero(&hunk->final_commit_id);
+ return hunk && git_oid_is_zero(&hunk->final_commit_id);
}
static int buffer_hunk_cb(
return 0;
}
-int git_blame_init_options(git_blame_options *opts, unsigned int version)
+int git_blame_options_init(git_blame_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_blame_options, GIT_BLAME_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_blame_init_options(git_blame_options *opts, unsigned int version)
+{
+ return git_blame_options_init(opts, version);
+}
+#endif
git_blame__entry *ent;
int num_lines;
const char *final_buf;
- git_off_t final_buf_size;
+ size_t final_buf_size;
};
git_blame *git_blame__alloc(
* split_overlap() divided an existing blame e into up to three parts in split.
* Adjust the linked list of blames in the scoreboard to reflect the split.
*/
-static void split_blame(git_blame *blame, git_blame__entry *split, git_blame__entry *e)
+static int split_blame(git_blame *blame, git_blame__entry *split, git_blame__entry *e)
{
git_blame__entry *new_entry;
/* The last part -- me */
new_entry = git__malloc(sizeof(*new_entry));
+ GIT_ERROR_CHECK_ALLOC(new_entry);
memcpy(new_entry, &(split[2]), sizeof(git_blame__entry));
add_blame_entry(blame, new_entry);
/* ... and the middle part -- parent */
new_entry = git__malloc(sizeof(*new_entry));
+ GIT_ERROR_CHECK_ALLOC(new_entry);
memcpy(new_entry, &(split[1]), sizeof(git_blame__entry));
add_blame_entry(blame, new_entry);
} else if (!split[0].suspect && !split[2].suspect) {
/* me and then parent */
dup_entry(e, &split[0]);
new_entry = git__malloc(sizeof(*new_entry));
+ GIT_ERROR_CHECK_ALLOC(new_entry);
memcpy(new_entry, &(split[1]), sizeof(git_blame__entry));
add_blame_entry(blame, new_entry);
} else {
/* parent and then me */
dup_entry(e, &split[1]);
new_entry = git__malloc(sizeof(*new_entry));
+ GIT_ERROR_CHECK_ALLOC(new_entry);
memcpy(new_entry, &(split[2]), sizeof(git_blame__entry));
add_blame_entry(blame, new_entry);
}
+
+ return 0;
}
/*
* Helper for blame_chunk(). blame_entry e is known to overlap with the patch
* hunk; split it and pass blame to the parent.
*/
-static void blame_overlap(
+static int blame_overlap(
git_blame *blame,
git_blame__entry *e,
size_t tlno,
split_overlap(split, e, tlno, plno, same, parent);
if (split[1].suspect)
- split_blame(blame, split, e);
+ if (split_blame(blame, split, e) < 0)
+ return -1;
decref_split(split);
+
+ return 0;
}
/*
* e and its parent. Find and split the overlap, and pass blame to the
* overlapping part to the parent.
*/
-static void blame_chunk(
+static int blame_chunk(
git_blame *blame,
size_t tlno,
size_t plno,
if (same <= e->s_lno)
continue;
if (tlno < e->s_lno + e->num_lines) {
- blame_overlap(blame, e, tlno, plno, same, parent);
+ if (blame_overlap(blame, e, tlno, plno, same, parent) < 0)
+ return -1;
}
}
+
+ return 0;
}
static int my_emit(
{
blame_chunk_cb_data *d = (blame_chunk_cb_data *)cb_data;
- blame_chunk(d->blame, d->tlno, d->plno, start_b, d->target, d->parent);
+ if (blame_chunk(d->blame, d->tlno, d->plno, start_b, d->target, d->parent) < 0)
+ return -1;
d->plno = start_a + count_a;
d->tlno = start_b + count_b;
b->size -= trimmed - recovered;
}
-static int diff_hunks(mmfile_t file_a, mmfile_t file_b, void *cb_data)
+static int diff_hunks(mmfile_t file_a, mmfile_t file_b, void *cb_data, git_blame_options *options)
{
- xpparam_t xpp = {0};
xdemitconf_t xecfg = {0};
xdemitcb_t ecb = {0};
+ xpparam_t xpp = {0};
+
+ if (options->flags & GIT_BLAME_IGNORE_WHITESPACE)
+ xpp.flags |= XDF_IGNORE_WHITESPACE;
xecfg.hunk_func = my_emit;
ecb.priv = cb_data;
fill_origin_blob(parent, &file_p);
fill_origin_blob(target, &file_o);
- if (diff_hunks(file_p, file_o, &d) < 0)
+ if (diff_hunks(file_p, file_o, &d, &blame->options) < 0)
return -1;
/* The reset (i.e. anything after tlno) are the same as the parent */
- blame_chunk(blame, d.tlno, d.plno, last_in_target, target, parent);
+ if (blame_chunk(blame, d.tlno, d.plno, last_in_target, target, parent) < 0)
+ return -1;
return 0;
}
return git_odb_object_data(blob->data.odb);
}
-git_off_t git_blob_rawsize(const git_blob *blob)
+git_object_size_t git_blob_rawsize(const git_blob *blob)
{
assert(blob);
if (blob->raw)
return blob->data.raw.size;
else
- return (git_off_t)git_odb_object_size(blob->data.odb);
+ return (git_object_size_t)git_odb_object_size(blob->data.odb);
}
int git_blob__getbuf(git_buf *buffer, git_blob *blob)
{
- git_off_t size = git_blob_rawsize(blob);
+ git_object_size_t size = git_blob_rawsize(blob);
GIT_ERROR_CHECK_BLOBSIZE(size);
return git_buf_set(buffer, git_blob_rawcontent(blob), (size_t)size);
return 0;
}
-int git_blob_create_frombuffer(
+int git_blob_create_from_buffer(
git_oid *id, git_repository *repo, const void *buffer, size_t len)
{
int error;
}
static int write_file_stream(
- git_oid *id, git_odb *odb, const char *path, git_off_t file_size)
+ git_oid *id, git_odb *odb, const char *path, git_object_size_t file_size)
{
int fd, error;
char buffer[FILEIO_BUFSIZE];
git_odb_stream *stream = NULL;
ssize_t read_len = -1;
- git_off_t written = 0;
+ git_object_size_t written = 0;
if ((error = git_odb_open_wstream(
&stream, odb, file_size, GIT_OBJECT_BLOB)) < 0)
static int write_file_filtered(
git_oid *id,
- git_off_t *size,
+ git_object_size_t *size,
git_odb *odb,
const char *full_path,
git_filter_list *fl)
int error;
struct stat st;
git_odb *odb = NULL;
- git_off_t size;
+ git_object_size_t size;
mode_t mode;
git_buf path = GIT_BUF_INIT;
return error;
}
-int git_blob_create_fromworkdir(
+int git_blob_create_from_workdir(
git_oid *id, git_repository *repo, const char *path)
{
return git_blob__create_from_paths(id, NULL, repo, NULL, path, 0, true);
}
-int git_blob_create_fromdisk(
+int git_blob_create_from_disk(
git_oid *id, git_repository *repo, const char *path)
{
int error;
return git_filebuf_write(&stream->fbuf, buffer, len);
}
-int git_blob_create_fromstream(git_writestream **out, git_repository *repo, const char *hintpath)
+int git_blob_create_from_stream(git_writestream **out, git_repository *repo, const char *hintpath)
{
int error;
git_buf path = GIT_BUF_INIT;
return error;
}
-int git_blob_create_fromstream_commit(git_oid *out, git_writestream *_stream)
+int git_blob_create_from_stream_commit(git_oid *out, git_writestream *_stream)
{
int error;
blob_writestream *stream = (blob_writestream *) _stream;
int git_blob_is_binary(const git_blob *blob)
{
git_buf content = GIT_BUF_INIT;
- git_off_t size;
+ git_object_size_t size;
assert(blob);
return git_buf_text_is_binary(&content);
}
-int git_blob_filtered_content(
+int git_blob_filter(
git_buf *out,
git_blob *blob,
const char *path,
- int check_for_binary_data)
+ git_blob_filter_options *given_opts)
{
int error = 0;
git_filter_list *fl = NULL;
+ git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
+ git_filter_flag_t flags = GIT_FILTER_DEFAULT;
assert(blob && path && out);
git_buf_sanitize(out);
- if (check_for_binary_data && git_blob_is_binary(blob))
+ GIT_ERROR_CHECK_VERSION(
+ given_opts, GIT_BLOB_FILTER_OPTIONS_VERSION, "git_blob_filter_options");
+
+ if (given_opts != NULL)
+ memcpy(&opts, given_opts, sizeof(git_blob_filter_options));
+
+ if ((opts.flags & GIT_BLOB_FILTER_CHECK_FOR_BINARY) != 0 &&
+ git_blob_is_binary(blob))
return 0;
+ if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
+ flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES;
+
+ if ((opts.flags & GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD) != 0)
+ flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD;
+
if (!(error = git_filter_list_load(
&fl, git_blob_owner(blob), blob, path,
- GIT_FILTER_TO_WORKTREE, GIT_FILTER_DEFAULT))) {
+ GIT_FILTER_TO_WORKTREE, flags))) {
error = git_filter_list_apply_to_blob(out, fl, blob);
return error;
}
+
+/* Deprecated functions */
+
+#ifndef GIT_DEPRECATE_HARD
+int git_blob_create_frombuffer(
+ git_oid *id, git_repository *repo, const void *buffer, size_t len)
+{
+ return git_blob_create_from_buffer(id, repo, buffer, len);
+}
+
+int git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path)
+{
+ return git_blob_create_from_workdir(id, repo, relative_path);
+}
+
+int git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path)
+{
+ return git_blob_create_from_disk(id, repo, path);
+}
+
+int git_blob_create_fromstream(
+ git_writestream **out,
+ git_repository *repo,
+ const char *hintpath)
+{
+ return git_blob_create_from_stream(out, repo, hintpath);
+}
+
+int git_blob_create_fromstream_commit(
+ git_oid *out,
+ git_writestream *stream)
+{
+ return git_blob_create_from_stream_commit(out, stream);
+}
+
+int git_blob_filtered_content(
+ git_buf *out,
+ git_blob *blob,
+ const char *path,
+ int check_for_binary_data)
+{
+ git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
+
+ if (check_for_binary_data)
+ opts.flags |= GIT_BLOB_FILTER_CHECK_FOR_BINARY;
+ else
+ opts.flags &= ~GIT_BLOB_FILTER_CHECK_FOR_BINARY;
+
+ return git_blob_filter(out, blob, path, &opts);
+}
+#endif
#include "git2/blob.h"
#include "repository.h"
#include "odb.h"
-#include "fileops.h"
+#include "futils.h"
struct git_blob {
git_object object;
git_odb_object *odb;
struct {
const char *data;
- git_off_t size;
+ git_object_size_t size;
} raw;
} data;
unsigned int raw:1;
git_reference **branch_reference_out,
git_repository *repo,
const char *branch_name,
- int is_remote)
+ bool is_remote)
{
git_reference *branch = NULL;
int error = 0;
repository, branch_name, commit->commit, commit->description, force);
}
-static int branch_equals(git_repository *repo, const char *path, void *payload)
+static int branch_is_checked_out(git_repository *worktree, void *payload)
{
git_reference *branch = (git_reference *) payload;
git_reference *head = NULL;
- int equal = 0;
+ int error;
- if (git_reference__read_head(&head, repo, path) < 0 ||
- git_reference_type(head) != GIT_REFERENCE_SYMBOLIC)
- goto done;
+ if (git_repository_is_bare(worktree))
+ return 0;
- equal = !git__strcmp(head->target.symbolic, branch->name);
+ if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) {
+ if (error == GIT_ENOTFOUND)
+ error = 0;
+ goto out;
+ }
-done:
+ if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC)
+ goto out;
+
+ error = !git__strcmp(head->target.symbolic, branch->name);
+
+out:
git_reference_free(head);
- return equal;
+ return error;
}
int git_branch_is_checked_out(const git_reference *branch)
{
- assert(branch && git_reference_is_branch(branch));
-
- return git_repository_foreach_head(git_reference_owner(branch),
- branch_equals, (void *) branch) == 1;
+ if (!git_reference_is_branch(branch))
+ return 0;
+ return git_repository_foreach_worktree(git_reference_owner(branch),
+ branch_is_checked_out, (void *)branch) == 1;
}
int git_branch_delete(git_reference *branch)
const char *branch_name,
git_branch_t branch_type)
{
+ int error = -1;
assert(ref_out && repo && branch_name);
- return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
+ switch (branch_type) {
+ case GIT_BRANCH_LOCAL:
+ case GIT_BRANCH_REMOTE:
+ error = retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
+ break;
+ case GIT_BRANCH_ALL:
+ error = retrieve_branch_reference(ref_out, repo, branch_name, false);
+ if (error == GIT_ENOTFOUND)
+ error = retrieve_branch_reference(ref_out, repo, branch_name, true);
+ break;
+ default:
+ assert(false);
+ }
+ return error;
}
int git_branch_name(
if (error < 0)
git_buf_dispose(buf);
- git_strarray_free(&remote_list);
+ git_strarray_dispose(&remote_list);
return error;
}
return -1;
}
-int git_branch_set_upstream(git_reference *branch, const char *upstream_name)
+int git_branch_set_upstream(git_reference *branch, const char *branch_name)
{
- git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT;
+ git_buf key = GIT_BUF_INIT, remote_name = GIT_BUF_INIT, merge_refspec = GIT_BUF_INIT;
git_reference *upstream;
git_repository *repo;
git_remote *remote = NULL;
git_config *config;
- const char *name, *shortname;
+ const char *refname, *shortname;
int local, error;
const git_refspec *fetchspec;
- name = git_reference_name(branch);
- if (!git_reference__is_branch(name))
- return not_a_local_branch(name);
+ refname = git_reference_name(branch);
+ if (!git_reference__is_branch(refname))
+ return not_a_local_branch(refname);
if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
return -1;
- shortname = name + strlen(GIT_REFS_HEADS_DIR);
+ shortname = refname + strlen(GIT_REFS_HEADS_DIR);
- if (upstream_name == NULL)
+ /* We're unsetting, delegate and bail-out */
+ if (branch_name == NULL)
return unset_upstream(config, shortname);
repo = git_reference_owner(branch);
- /* First we need to figure out whether it's a branch or remote-tracking */
- if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0)
+ /* First we need to resolve name to a branch */
+ if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_LOCAL) == 0)
local = 1;
- else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0)
+ else if (git_branch_lookup(&upstream, repo, branch_name, GIT_BRANCH_REMOTE) == 0)
local = 0;
else {
git_error_set(GIT_ERROR_REFERENCE,
}
/*
- * If it's local, the remote is "." and the branch name is
- * simply the refname. Otherwise we need to figure out what
- * the remote-tracking branch's name on the remote is and use
- * that.
+ * If it's a local-tracking branch, its remote is "." (as "the local
+ * repository"), and the branch name is simply the refname.
+ * Otherwise we need to figure out what the remote-tracking branch's
+ * name on the remote is and use that.
*/
if (local)
- error = git_buf_puts(&value, ".");
+ error = git_buf_puts(&remote_name, ".");
else
- error = git_branch_remote_name(&value, repo, git_reference_name(upstream));
+ error = git_branch_remote_name(&remote_name, repo, git_reference_name(upstream));
if (error < 0)
goto on_error;
+ /* Update the upsteam branch config with the new name */
if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0)
goto on_error;
- if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
+ if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&remote_name)) < 0)
goto on_error;
if (local) {
- git_buf_clear(&value);
- if (git_buf_puts(&value, git_reference_name(upstream)) < 0)
+ /* A local branch uses the upstream refname directly */
+ if (git_buf_puts(&merge_refspec, git_reference_name(upstream)) < 0)
goto on_error;
} else {
- /* Get the remoe-tracking branch's refname in its repo */
- if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0)
+ /* We transform the upstream branch name according to the remote's refspecs */
+ if (git_remote_lookup(&remote, repo, git_buf_cstr(&remote_name)) < 0)
goto on_error;
fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream));
- git_buf_clear(&value);
- if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0)
+ if (!fetchspec || git_refspec_rtransform(&merge_refspec, fetchspec, git_reference_name(upstream)) < 0)
goto on_error;
git_remote_free(remote);
remote = NULL;
}
+ /* Update the merge branch config with the refspec */
git_buf_clear(&key);
if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0)
goto on_error;
- if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0)
+ if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&merge_refspec)) < 0)
goto on_error;
git_reference_free(upstream);
git_buf_dispose(&key);
- git_buf_dispose(&value);
+ git_buf_dispose(&remote_name);
+ git_buf_dispose(&merge_refspec);
return 0;
on_error:
git_reference_free(upstream);
git_buf_dispose(&key);
- git_buf_dispose(&value);
+ git_buf_dispose(&remote_name);
+ git_buf_dispose(&merge_refspec);
git_remote_free(remote);
return -1;
char git_buf__oom[1];
#define ENSURE_SIZE(b, d) \
- if ((d) > (b)->asize && git_buf_grow((b), (d)) < 0)\
+ if ((b)->ptr == git_buf__oom || \
+ ((d) > (b)->asize && git_buf_grow((b), (d)) < 0))\
return -1;
new_ptr = NULL;
} else {
new_size = buf->asize;
+ /*
+ * Grow the allocated buffer by 1.5 to allow
+ * re-use of memory holes resulting from the
+ * realloc. If this is still too small, then just
+ * use the target size.
+ */
+ if ((new_size = (new_size << 1) - (new_size >> 1)) < target_size)
+ new_size = target_size;
new_ptr = buf->ptr;
}
- /* grow the buffer size by 1.5, until it's big enough
- * to fit our target size */
- while (new_size < target_size)
- new_size = (new_size << 1) - (new_size >> 1);
-
/* round allocation up to multiple of 8 */
new_size = (new_size + 7) & ~7;
if (new_size < buf->size) {
- if (mark_oom)
+ if (mark_oom) {
+ if (buf->ptr && buf->ptr != git_buf__initbuf)
+ git__free(buf->ptr);
buf->ptr = git_buf__oom;
+ }
git_error_set_oom();
return -1;
git_buf_init(buf, 0);
}
+#ifndef GIT_DEPRECATE_HARD
void git_buf_free(git_buf *buf)
{
git_buf_dispose(buf);
}
+#endif
void git_buf_sanitize(git_buf *buf)
{
for (i = 24; i >= 0; i -= 8) {
uint8_t ch = *data++;
- acc |= ch << i;
+ acc |= (uint32_t)ch << i;
if (--len == 0)
break;
data[copylen] = '\0';
}
+void git_buf_consume_bytes(git_buf *buf, size_t len)
+{
+ git_buf_consume(buf, buf->ptr + len);
+}
+
void git_buf_consume(git_buf *buf, const char *end)
{
if (end > buf->ptr && end <= buf->ptr + buf->size) {
ssize_t offset_a = -1;
/* not safe to have str_b point internally to the buffer */
- assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
+ if (buf->size)
+ assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
/* figure out if we need to insert a separator */
if (separator && strlen_a) {
}
/* str_a could be part of the buffer */
- if (str_a >= buf->ptr && str_a < buf->ptr + buf->size)
+ if (buf->size && str_a >= buf->ptr && str_a < buf->ptr + buf->size)
offset_a = str_a - buf->ptr;
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, strlen_a, strlen_b);
int git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap);
void git_buf_clear(git_buf *buf);
+void git_buf_consume_bytes(git_buf *buf, size_t len);
void git_buf_consume(git_buf *buf, const char *end);
void git_buf_truncate(git_buf *buf, size_t len);
void git_buf_shorten(git_buf *buf, size_t amount);
return 0;
}
-void git_cache_dump_stats(git_cache *cache)
-{
- git_cached_obj *object;
-
- if (git_cache_size(cache) == 0)
- return;
-
- printf("Cache %p: %"PRIuZ" items cached, %"PRIdZ" bytes\n",
- cache, git_cache_size(cache), cache->used_memory);
-
- git_oidmap_foreach_value(cache->map, object, {
- char oid_str[9];
- printf(" %s%c %s (%"PRIuZ")\n",
- git_object_type2string(object->type),
- object->flags == GIT_CACHE_STORE_PARSED ? '*' : ' ',
- git_oid_tostr(oid_str, sizeof(oid_str), &object->oid),
- object->size
- );
- });
-}
-
int git_cache_init(git_cache *cache)
{
memset(cache, 0, sizeof(*cache));
- cache->map = git_oidmap_alloc();
- GIT_ERROR_CHECK_ALLOC(cache->map);
+
+ if ((git_oidmap_new(&cache->map)) < 0)
+ return -1;
+
if (git_rwlock_init(&cache->lock)) {
git_error_set(GIT_ERROR_OS, "failed to initialize cache rwlock");
return -1;
}
+
return 0;
}
git_rwlock_wrunlock(&cache->lock);
}
-void git_cache_free(git_cache *cache)
+void git_cache_dispose(git_cache *cache)
{
git_cache_clear(cache);
git_oidmap_free(cache->map);
/* Called with lock */
static void cache_evict_entries(git_cache *cache)
{
- uint32_t seed = rand();
- size_t evict_count = 8;
+ size_t evict_count = git_cache_size(cache) / 2048, i;
ssize_t evicted_memory = 0;
+ if (evict_count < 8)
+ evict_count = 8;
+
/* do not infinite loop if there's not enough entries to evict */
if (evict_count > git_cache_size(cache)) {
clear_cache(cache);
return;
}
+ i = 0;
while (evict_count > 0) {
- size_t pos = seed++ % git_oidmap_end(cache->map);
-
- if (git_oidmap_has_data(cache->map, pos)) {
- git_cached_obj *evict = git_oidmap_value_at(cache->map, pos);
+ git_cached_obj *evict;
+ const git_oid *key;
- evict_count--;
- evicted_memory += evict->size;
- git_cached_obj_decref(evict);
+ if (git_oidmap_iterate((void **) &evict, cache->map, &i, &key) == GIT_ITEROVER)
+ break;
- git_oidmap_delete_at(cache->map, pos);
- }
+ evict_count--;
+ evicted_memory += evict->size;
+ git_oidmap_delete(cache->map, key);
+ git_cached_obj_decref(evict);
}
cache->used_memory -= evicted_memory;
static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
{
- size_t pos;
- git_cached_obj *entry = NULL;
+ git_cached_obj *entry;
if (!git_cache__enabled || git_rwlock_rdlock(&cache->lock) < 0)
return NULL;
- pos = git_oidmap_lookup_index(cache->map, oid);
- if (git_oidmap_valid_index(cache->map, pos)) {
- entry = git_oidmap_value_at(cache->map, pos);
-
+ if ((entry = git_oidmap_get(cache->map, oid)) != NULL) {
if (flags && entry->flags != flags) {
entry = NULL;
} else {
static void *cache_store(git_cache *cache, git_cached_obj *entry)
{
- size_t pos;
+ git_cached_obj *stored_entry;
git_cached_obj_incref(entry);
return entry;
/* soften the load on the cache */
- if (git_cache__current_storage.val > git_cache__max_storage)
+ if (git_atomic_ssize_get(&git_cache__current_storage) > git_cache__max_storage)
cache_evict_entries(cache);
- pos = git_oidmap_lookup_index(cache->map, &entry->oid);
-
/* not found */
- if (!git_oidmap_valid_index(cache->map, pos)) {
- int rval;
-
- git_oidmap_insert(cache->map, &entry->oid, entry, &rval);
- if (rval >= 0) {
+ if ((stored_entry = git_oidmap_get(cache->map, &entry->oid)) == NULL) {
+ if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) {
git_cached_obj_incref(entry);
cache->used_memory += entry->size;
git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size);
}
/* found */
else {
- git_cached_obj *stored_entry = git_oidmap_value_at(cache->map, pos);
-
if (stored_entry->flags == entry->flags) {
git_cached_obj_decref(entry);
git_cached_obj_incref(stored_entry);
entry = stored_entry;
} else if (stored_entry->flags == GIT_CACHE_STORE_RAW &&
- entry->flags == GIT_CACHE_STORE_PARSED) {
- git_cached_obj_decref(stored_entry);
- git_cached_obj_incref(entry);
-
- git_oidmap_set_key_at(cache->map, pos, &entry->oid);
- git_oidmap_set_value_at(cache->map, pos, entry);
+ entry->flags == GIT_CACHE_STORE_PARSED) {
+ if (git_oidmap_set(cache->map, &entry->oid, entry) == 0) {
+ git_cached_obj_decref(stored_entry);
+ git_cached_obj_incref(entry);
+ } else {
+ git_cached_obj_decref(entry);
+ git_cached_obj_incref(stored_entry);
+ entry = stored_entry;
+ }
} else {
/* NO OP */
}
int git_cache_set_max_object_size(git_object_t type, size_t size);
int git_cache_init(git_cache *cache);
-void git_cache_free(git_cache *cache);
+void git_cache_dispose(git_cache *cache);
void git_cache_clear(git_cache *cache);
void *git_cache_store_raw(git_cache *cache, git_odb_object *entry);
/* Define the printf format specifer to use for size_t output */
#if defined(_MSC_VER) || defined(__MINGW32__)
+/* Visual Studio 2012 and prior lack PRId64 entirely */
+# ifndef PRId64
+# define PRId64 "I64d"
+# endif
+
/* The first block is needed to avoid warnings on MingW amd64 */
# if (SIZE_MAX == ULLONG_MAX)
# define PRIuZ "I64u"
#include "checkout.h"
-#include <assert.h>
-
#include "git2/repository.h"
#include "git2/refs.h"
#include "git2/tree.h"
CHECKOUT_ACTION__REMOVE_CONFLICT = 16,
CHECKOUT_ACTION__UPDATE_CONFLICT = 32,
CHECKOUT_ACTION__MAX = 32,
- CHECKOUT_ACTION__DEFER_REMOVE = 64,
CHECKOUT_ACTION__REMOVE_AND_UPDATE =
(CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
};
}
if (git_submodule_status(&sm_status, data->repo, wditem->path, GIT_SUBMODULE_IGNORE_UNSPECIFIED) < 0 ||
- GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
+ GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
rval = true;
else if ((sm_oid = git_submodule_wd_id(sm)) == NULL)
rval = false;
ie = git_index_get_bypath(data->index, wditem->path, 0);
if (ie != NULL &&
- git_index_time_eq(&wditem->mtime, &ie->mtime) &&
- wditem->file_size == ie->file_size &&
- !is_filemode_changed(wditem->mode, ie->mode, data->respect_filemode)) {
+ !git_index_entry_newer_than_index(ie, data->index) &&
+ git_index_time_eq(&wditem->mtime, &ie->mtime) &&
+ wditem->file_size == ie->file_size &&
+ !is_filemode_changed(wditem->mode, ie->mode, data->respect_filemode)) {
/* The workdir is modified iff the index entry is modified */
return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
/* if the file is on disk and doesn't match our mode, force update */
if (wd &&
- GIT_PERMS_IS_EXEC(wd->mode) !=
- GIT_PERMS_IS_EXEC(delta->new_file.mode))
- *action |= CHECKOUT_ACTION__REMOVE;
+ GIT_PERMS_IS_EXEC(wd->mode) != GIT_PERMS_IS_EXEC(delta->new_file.mode))
+ *action |= CHECKOUT_ACTION__REMOVE;
notify = GIT_CHECKOUT_NOTIFY_UPDATED;
}
if (!git_pathspec__match(
pathspec, wd->path,
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
- git_iterator_ignore_case(workdir), NULL, NULL))
- return git_iterator_advance(wditem, workdir);
+ git_iterator_ignore_case(workdir), NULL, NULL)) {
+
+ if (wd->mode == GIT_FILEMODE_TREE)
+ return git_iterator_advance_into(wditem, workdir);
+ else
+ return git_iterator_advance(wditem, workdir);
+ }
/* check if item is tracked in the index but not in the checkout diff */
if (data->index != NULL) {
int diff;
if ((diff = checkout_idxentry_cmp(ca->ancestor, cb->ancestor)) == 0 &&
- (diff = checkout_idxentry_cmp(ca->ours, cb->theirs)) == 0)
+ (diff = checkout_idxentry_cmp(ca->ours, cb->theirs)) == 0)
diff = checkout_idxentry_cmp(ca->theirs, cb->theirs);
return diff;
}
-int checkout_conflictdata_empty(
+static int checkout_conflictdata_empty(
const git_vector *conflicts, size_t idx, void *payload)
{
checkout_conflictdata *conflict;
/* Find d/f conflicts */
git_vector_foreach(&data->update_conflicts, i, conflict) {
if ((conflict->ours && conflict->theirs) ||
- (!conflict->ours && !conflict->theirs))
+ (!conflict->ours && !conflict->theirs))
continue;
path = conflict->ours ?
return 0;
if ((error = checkout_conflicts_load(data, workdir, pathspec)) < 0 ||
- (error = checkout_conflicts_coalesce_renames(data)) < 0 ||
- (error = checkout_conflicts_mark_directoryfile(data)) < 0)
+ (error = checkout_conflicts_coalesce_renames(data)) < 0 ||
+ (error = checkout_conflicts_mark_directoryfile(data)) < 0)
goto done;
done:
size_t i, *counts = NULL;
uint32_t *actions = NULL;
- git_pool_init(&pathpool, 1);
+ if (git_pool_init(&pathpool, 1) < 0)
+ return -1;
if (data->opts.paths.count > 0 &&
- git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
+ git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
return -1;
if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
- error != GIT_ITEROVER)
+ error != GIT_ITEROVER)
goto fail;
deltas = &data->diff->deltas;
counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
- (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
- {
+ (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0) {
git_error_set(GIT_ERROR_CHECKOUT, "%"PRIuZ" %s checkout",
counts[CHECKOUT_ACTION__CONFLICT],
counts[CHECKOUT_ACTION__CONFLICT] == 1 ?
if ((error = checkout_get_remove_conflicts(data, workdir, &pathspec)) < 0 ||
- (error = checkout_get_update_conflicts(data, workdir, &pathspec)) < 0)
+ (error = checkout_get_update_conflicts(data, workdir, &pathspec)) < 0)
goto fail;
counts[CHECKOUT_ACTION__REMOVE_CONFLICT] = git_vector_length(&data->remove_conflicts);
{
int ignorecase;
- if (git_repository__cvar(&ignorecase, data->repo, GIT_CVAR_IGNORECASE) < 0) {
+ if (git_repository__configmap_lookup(&ignorecase, data->repo, GIT_CONFIGMAP_IGNORECASE) < 0) {
ignorecase = 0;
}
return 0;
}
-static int checkout_deferred_remove(git_repository *repo, const char *path)
-{
-#if 0
- int error = git_futils_rmdir_r(
- path, data->opts.target_directory, GIT_RMDIR_EMPTY_PARENTS);
-
- if (error == GIT_ENOTFOUND) {
- error = 0;
- git_error_clear();
- }
-
- return error;
-#else
- GIT_UNUSED(repo);
- GIT_UNUSED(path);
- assert(false);
- return 0;
-#endif
-}
-
static int checkout_create_the_new(
unsigned int *actions,
checkout_data *data)
size_t i;
git_vector_foreach(&data->diff->deltas, i, delta) {
- if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
- /* this had a blocker directory that should only be removed iff
- * all of the contents of the directory were safely removed
- */
- if ((error = checkout_deferred_remove(
- data->repo, delta->old_file.path)) < 0)
+ if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB && !S_ISLNK(delta->new_file.mode)) {
+ if ((error = checkout_blob(data, &delta->new_file)) < 0)
return error;
+ data->completed_steps++;
+ report_progress(data, delta->new_file.path);
}
+ }
- if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) {
- error = checkout_blob(data, &delta->new_file);
- if (error < 0)
+ git_vector_foreach(&data->diff->deltas, i, delta) {
+ if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB && S_ISLNK(delta->new_file.mode)) {
+ if ((error = checkout_blob(data, &delta->new_file)) < 0)
return error;
-
data->completed_steps++;
report_progress(data, delta->new_file.path);
}
unsigned int *actions,
checkout_data *data)
{
- int error = 0;
git_diff_delta *delta;
size_t i;
git_vector_foreach(&data->diff->deltas, i, delta) {
- if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
- /* this has a blocker directory that should only be removed iff
- * all of the contents of the directory were safely removed
- */
- if ((error = checkout_deferred_remove(
- data->repo, delta->old_file.path)) < 0)
- return error;
- }
-
if (actions[i] & CHECKOUT_ACTION__UPDATE_SUBMODULE) {
int error = checkout_submodule(data, &delta->new_file);
if (error < 0)
data->pfx = git_pathspec_prefix(&data->opts.paths);
- if ((error = git_repository__cvar(
- &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
+ if ((error = git_repository__configmap_lookup(
+ &data->can_symlink, repo, GIT_CONFIGMAP_SYMLINKS)) < 0)
goto cleanup;
- if ((error = git_repository__cvar(
- &data->respect_filemode, repo, GIT_CVAR_FILEMODE)) < 0)
+ if ((error = git_repository__configmap_lookup(
+ &data->respect_filemode, repo, GIT_CONFIGMAP_FILEMODE)) < 0)
goto cleanup;
if (!data->opts.baseline && !data->opts.baseline_index) {
git_config_entry_free(conflict_style);
}
- git_pool_init(&data->pool, 1);
-
- if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
- (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 ||
- (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
- (error = git_buf_puts(&data->target_path, data->opts.target_directory)) < 0 ||
- (error = git_path_to_dir(&data->target_path)) < 0 ||
- (error = git_strmap_alloc(&data->mkdir_map)) < 0)
+ if ((error = git_pool_init(&data->pool, 1)) < 0 ||
+ (error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
+ (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 ||
+ (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
+ (error = git_buf_puts(&data->target_path, data->opts.target_directory)) < 0 ||
+ (error = git_path_to_dir(&data->target_path)) < 0 ||
+ (error = git_strmap_new(&data->mkdir_map)) < 0)
goto cleanup;
data->target_len = git_buf_len(&data->target_path);
#define CHECKOUT_INDEX_DONT_WRITE_MASK \
(GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
+GIT_INLINE(void) setup_pathspecs(
+ git_iterator_options *iter_opts,
+ const git_checkout_options *checkout_opts)
+{
+ if (checkout_opts &&
+ (checkout_opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
+ iter_opts->pathlist.count = checkout_opts->paths.count;
+ iter_opts->pathlist.strings = checkout_opts->paths.strings;
+ }
+}
+
int git_checkout_iterator(
git_iterator *target,
git_index *index,
workdir_opts.start = data.pfx;
workdir_opts.end = data.pfx;
+ setup_pathspecs(&workdir_opts, opts);
+
if ((error = git_iterator_reset_range(target, data.pfx, data.pfx)) < 0 ||
(error = git_iterator_for_workdir_ext(
&workdir, data.repo, data.opts.target_directory, index, NULL,
GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
baseline_opts.start = data.pfx;
baseline_opts.end = data.pfx;
- if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
- baseline_opts.pathlist.count = opts->paths.count;
- baseline_opts.pathlist.strings = opts->paths.strings;
- }
+
+ setup_pathspecs(&baseline_opts, opts);
if (data.opts.baseline_index) {
if ((error = git_iterator_for_index(
git_index *index,
const git_checkout_options *opts)
{
+ git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
int error, owned = 0;
git_iterator *index_i;
return error;
GIT_REFCOUNT_INC(index);
- if (!(error = git_iterator_for_index(&index_i, repo, index, NULL)))
+ setup_pathspecs(&iter_opts, opts);
+
+ if (!(error = git_iterator_for_index(&index_i, repo, index, &iter_opts)))
error = git_checkout_iterator(index_i, index, opts);
if (owned)
if ((error = git_repository_index(&index, repo)) < 0)
return error;
- if (opts && (opts->checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)) {
- iter_opts.pathlist.count = opts->paths.count;
- iter_opts.pathlist.strings = opts->paths.strings;
- }
+ setup_pathspecs(&iter_opts, opts);
if (!(error = git_iterator_for_tree(&tree_i, tree, &iter_opts)))
error = git_checkout_iterator(tree_i, index, opts);
return git_checkout_tree(repo, NULL, opts);
}
-int git_checkout_init_options(git_checkout_options *opts, unsigned int version)
+int git_checkout_options_init(git_checkout_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_checkout_options, GIT_CHECKOUT_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_checkout_init_options(git_checkout_options *opts, unsigned int version)
+{
+ return git_checkout_options_init(opts, version);
+}
+#endif
int error = 0;
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_CHERRYPICK_HEAD_FILE)) >= 0 &&
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_CHERRYPICK_FILE_MODE)) >= 0 &&
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_CHERRYPICK_FILE_MODE)) >= 0 &&
(error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0)
error = git_filebuf_commit(&file);
int error = 0;
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_CHERRYPICK_FILE_MODE)) < 0 ||
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_CHERRYPICK_FILE_MODE)) < 0 ||
(error = git_filebuf_printf(&file, "%s", commit_msg)) < 0)
goto cleanup;
return error;
}
-int git_cherrypick_init_options(
+int git_cherrypick_options_init(
git_cherrypick_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_cherrypick_options, GIT_CHERRYPICK_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_cherrypick_init_options(
+ git_cherrypick_options *opts, unsigned int version)
+{
+ return git_cherrypick_options_init(opts, version);
+}
+#endif
#include "clone.h"
-#include <assert.h>
-
#include "git2/clone.h"
#include "git2/remote.h"
#include "git2/revparse.h"
#include "git2/tree.h"
#include "remote.h"
-#include "fileops.h"
+#include "futils.h"
#include "refs.h"
#include "path.h"
#include "repository.h"
return error;
}
+static int update_head_to_default(git_repository *repo)
+{
+ git_buf initialbranch = GIT_BUF_INIT;
+ const char *branch_name;
+ int error = 0;
+
+ if ((error = git_repository_initialbranch(&initialbranch, repo)) < 0)
+ goto done;
+
+ if (git__prefixcmp(initialbranch.ptr, GIT_REFS_HEADS_DIR) != 0) {
+ git_error_set(GIT_ERROR_INVALID, "invalid initial branch '%s'", initialbranch.ptr);
+ error = -1;
+ goto done;
+ }
+
+ branch_name = initialbranch.ptr + strlen(GIT_REFS_HEADS_DIR);
+
+ error = setup_tracking_config(repo, branch_name, GIT_REMOTE_ORIGIN,
+ initialbranch.ptr);
+
+done:
+ git_buf_dispose(&initialbranch);
+ return error;
+}
+
+static int update_remote_head(
+ git_repository *repo,
+ git_remote *remote,
+ git_buf *target,
+ const char *reflog_message)
+{
+ git_refspec *refspec;
+ git_reference *remote_head = NULL;
+ git_buf remote_head_name = GIT_BUF_INIT;
+ git_buf remote_branch_name = GIT_BUF_INIT;
+ int error;
+
+ /* Determine the remote tracking ref name from the local branch */
+ refspec = git_remote__matching_refspec(remote, git_buf_cstr(target));
+
+ if (refspec == NULL) {
+ git_error_set(GIT_ERROR_NET, "the remote's default branch does not fit the refspec configuration");
+ error = GIT_EINVALIDSPEC;
+ goto cleanup;
+ }
+
+ if ((error = git_refspec_transform(
+ &remote_branch_name,
+ refspec,
+ git_buf_cstr(target))) < 0)
+ goto cleanup;
+
+ if ((error = git_buf_printf(&remote_head_name,
+ "%s%s/%s",
+ GIT_REFS_REMOTES_DIR,
+ git_remote_name(remote),
+ GIT_HEAD_FILE)) < 0)
+ goto cleanup;
+
+ error = git_reference_symbolic_create(
+ &remote_head,
+ repo,
+ git_buf_cstr(&remote_head_name),
+ git_buf_cstr(&remote_branch_name),
+ true,
+ reflog_message);
+
+cleanup:
+ git_reference_free(remote_head);
+ git_buf_dispose(&remote_branch_name);
+ git_buf_dispose(&remote_head_name);
+ return error;
+}
+
static int update_head_to_remote(
git_repository *repo,
git_remote *remote,
{
int error = 0;
size_t refs_len;
- git_refspec *refspec;
const git_remote_head *remote_head, **refs;
const git_oid *remote_head_id;
- git_buf remote_master_name = GIT_BUF_INIT;
git_buf branch = GIT_BUF_INIT;
if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0)
/* We cloned an empty repository or one with an unborn HEAD */
if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_FILE))
- return setup_tracking_config(
- repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE);
+ return update_head_to_default(repo);
/* We know we have HEAD, let's see where it points */
remote_head = refs[0];
goto cleanup;
}
- refspec = git_remote__matching_refspec(remote, git_buf_cstr(&branch));
-
- if (refspec == NULL) {
- git_error_set(GIT_ERROR_NET, "the remote's default branch does not fit the refspec configuration");
- error = GIT_EINVALIDSPEC;
- goto cleanup;
- }
-
- /* Determine the remote tracking reference name from the local master */
- if ((error = git_refspec_transform(
- &remote_master_name,
- refspec,
- git_buf_cstr(&branch))) < 0)
+ if ((error = update_remote_head(repo, remote, &branch, reflog_message)) < 0)
goto cleanup;
error = update_head_to_new_branch(
reflog_message);
cleanup:
- git_buf_dispose(&remote_master_name);
git_buf_dispose(&branch);
return error;
return is_local;
}
-int git_clone(
+static int git__clone(
git_repository **out,
const char *url,
const char *local_path,
- const git_clone_options *_options)
+ const git_clone_options *_options,
+ int use_existing)
{
int error = 0;
git_repository *repo = NULL;
GIT_ERROR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options");
/* Only clone to a new directory or an empty directory */
- if (git_path_exists(local_path) && !git_path_is_empty_dir(local_path)) {
+ if (git_path_exists(local_path) && !use_existing && !git_path_is_empty_dir(local_path)) {
git_error_set(GIT_ERROR_INVALID,
"'%s' exists and is not an empty directory", local_path);
return GIT_EEXISTS;
return error;
}
-int git_clone_init_options(git_clone_options *opts, unsigned int version)
+int git_clone(
+ git_repository **out,
+ const char *url,
+ const char *local_path,
+ const git_clone_options *_options)
+{
+ return git__clone(out, url, local_path, _options, 0);
+}
+
+int git_clone__submodule(
+ git_repository **out,
+ const char *url,
+ const char *local_path,
+ const git_clone_options *_options)
+{
+ return git__clone(out, url, local_path, _options, 1);
+}
+
+int git_clone_options_init(git_clone_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_clone_options, GIT_CLONE_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_clone_init_options(git_clone_options *opts, unsigned int version)
+{
+ return git_clone_options_init(opts, version);
+}
+#endif
+
static bool can_link(const char *src, const char *dst, int link)
{
#ifdef GIT_WIN32
#include "git2/clone.h"
+extern int git_clone__submodule(git_repository **out,
+ const char *url, const char *local_path,
+ const git_clone_options *_options);
+
extern int git_clone__should_clone_local(const char *url, git_clone_local_t local);
#endif
#include "message.h"
#include "refs.h"
#include "object.h"
+#include "array.h"
#include "oidarray.h"
void git_commit__free(void *_commit)
}
static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree,
- git_commit_parent_callback parent_cb, void *parent_payload,
- const git_oid *current_id, bool validate)
+ git_commit_parent_callback parent_cb, void *parent_payload,
+ const git_oid *current_id, bool validate)
{
size_t i;
int error;
goto cleanup;
error = git_commit__create_buffer_internal(&buf, author, committer,
- message_encoding, message, tree,
- &parents);
+ message_encoding, message, tree,
+ &parents);
if (error < 0)
goto cleanup;
return error;
}
-int git_commit__parse_raw(void *_commit, const char *data, size_t size)
+static int commit_parse(git_commit *commit, const char *data, size_t size, unsigned int flags)
{
- git_commit *commit = _commit;
const char *buffer_start = data, *buffer;
const char *buffer_end = buffer_start + size;
git_oid parent_id;
size_t header_len;
git_signature dummy_sig;
+ assert(commit && data);
+
buffer = buffer_start;
/* Allocate for one, which will allow not to realloc 90% of the time */
GIT_ERROR_CHECK_ARRAY(commit->parent_ids);
/* The tree is always the first field */
- if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
- goto bad_buffer;
+ if (!(flags & GIT_COMMIT_PARSE_QUICK)) {
+ if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
+ goto bad_buffer;
+ } else {
+ size_t tree_len = strlen("tree ") + GIT_OID_HEXSZ + 1;
+ if (buffer + tree_len > buffer_end)
+ goto bad_buffer;
+ buffer += tree_len;
+ }
/*
* TODO: commit grafts!
git_oid_cpy(new_id, &parent_id);
}
- commit->author = git__malloc(sizeof(git_signature));
- GIT_ERROR_CHECK_ALLOC(commit->author);
+ if (!(flags & GIT_COMMIT_PARSE_QUICK)) {
+ commit->author = git__malloc(sizeof(git_signature));
+ GIT_ERROR_CHECK_ALLOC(commit->author);
- if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
- return -1;
+ if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
+ return -1;
+ }
/* Some tools create multiple author fields, ignore the extra ones */
while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) {
if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
return -1;
+ if (flags & GIT_COMMIT_PARSE_QUICK)
+ return 0;
+
/* Parse add'l header entries */
while (buffer < buffer_end) {
const char *eoln = buffer;
return -1;
}
+int git_commit__parse_raw(void *commit, const char *data, size_t size)
+{
+ return commit_parse(commit, data, size, 0);
+}
+
+int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags)
+{
+ return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags);
+}
+
int git_commit__parse(void *_commit, git_odb_object *odb_obj)
{
- return git_commit__parse_raw(_commit,
- git_odb_object_data(odb_obj),
- git_odb_object_size(odb_obj));
+ return git_commit__parse_ext(_commit, odb_obj, 0);
}
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
break;
if (*msg)
- commit->body = git__strndup(msg, end - msg + 1);
+ commit->body = git__strndup(msg, end - msg + 1);
}
return commit->body;
return error;
if (obj->cached.type != GIT_OBJECT_COMMIT) {
- git_error_set(GIT_ERROR_INVALID, "the requested type does not match the type in ODB");
+ git_error_set(GIT_ERROR_INVALID, "the requested type does not match the type in the ODB");
error = GIT_ENOTFOUND;
goto cleanup;
}
git_buf_putc(out, '\n');
}
+static const git_oid *commit_parent_from_commit(size_t n, void *payload)
+{
+ const git_commit *commit = (const git_commit *) payload;
+
+ return git_array_get(commit->parent_ids, n);
+
+}
+
int git_commit_create_with_signature(
git_oid *out,
git_repository *repo,
const char *field;
const char *header_end;
git_buf commit = GIT_BUF_INIT;
+ git_commit *parsed;
+ git_array_oid_t parents = GIT_ARRAY_INIT;
+
+ /* The first step is to verify that all the tree and parents exist */
+ parsed = git__calloc(1, sizeof(git_commit));
+ GIT_ERROR_CHECK_ALLOC(parsed);
+ if ((error = commit_parse(parsed, commit_content, strlen(commit_content), 0)) < 0)
+ goto cleanup;
+
+ if ((error = validate_tree_and_parents(&parents, repo, &parsed->tree_id, commit_parent_from_commit, parsed, NULL, true)) < 0)
+ goto cleanup;
- /* We start by identifying the end of the commit header */
+ git_array_clear(parents);
+
+ /* Then we start appending by identifying the end of the commit header */
header_end = strstr(commit_content, "\n\n");
if (!header_end) {
git_error_set(GIT_ERROR_INVALID, "malformed commit contents");
- return -1;
+ error = -1;
+ goto cleanup;
}
- field = signature_field ? signature_field : "gpgsig";
-
/* The header ends after the first LF */
header_end++;
git_buf_put(&commit, commit_content, header_end - commit_content);
- format_header_field(&commit, field, signature);
+
+ if (signature != NULL) {
+ field = signature_field ? signature_field : "gpgsig";
+ format_header_field(&commit, field, signature);
+ }
+
git_buf_puts(&commit, header_end);
if (git_buf_oom(&commit))
goto cleanup;
cleanup:
+ git_commit__free(parsed);
git_buf_dispose(&commit);
return error;
}
int git_commit__parse(void *commit, git_odb_object *obj);
int git_commit__parse_raw(void *commit, const char *data, size_t size);
+typedef enum {
+ GIT_COMMIT_PARSE_QUICK = (1 << 0), /**< Only parse parents and committer info */
+} git_commit__parse_flags;
+
+int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags);
+
#endif
#include "revwalk.h"
#include "pool.h"
#include "odb.h"
+#include "commit.h"
int git_commit_list_time_cmp(const void *a, const void *b)
{
return (git_commit_list_node *)git_pool_mallocz(&walk->commit_pool, 1);
}
-static int commit_error(git_commit_list_node *commit, const char *msg)
-{
- char commit_oid[GIT_OID_HEXSZ + 1];
- git_oid_fmt(commit_oid, &commit->oid);
- commit_oid[GIT_OID_HEXSZ] = '\0';
-
- git_error_set(GIT_ERROR_ODB, "failed to parse commit %s - %s", commit_oid, msg);
-
- return -1;
-}
-
static git_commit_list_node **alloc_parents(
git_revwalk *walk, git_commit_list_node *commit, size_t n_parents)
{
static int commit_quick_parse(
git_revwalk *walk,
- git_commit_list_node *commit,
- const uint8_t *buffer,
- size_t buffer_len)
+ git_commit_list_node *node,
+ git_odb_object *obj)
{
- const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1;
- const uint8_t *buffer_end = buffer + buffer_len;
- const uint8_t *parents_start, *committer_start;
- int i, parents = 0;
- int64_t commit_time;
-
- buffer += strlen("tree ") + GIT_OID_HEXSZ + 1;
-
- parents_start = buffer;
- while (buffer + parent_len < buffer_end && memcmp(buffer, "parent ", strlen("parent ")) == 0) {
- parents++;
- buffer += parent_len;
- }
-
- commit->parents = alloc_parents(walk, commit, parents);
- GIT_ERROR_CHECK_ALLOC(commit->parents);
-
- buffer = parents_start;
- for (i = 0; i < parents; ++i) {
- git_oid oid;
-
- if (git_oid_fromstr(&oid, (const char *)buffer + strlen("parent ")) < 0)
- return -1;
+ git_oid *parent_oid;
+ git_commit *commit;
+ int error;
+ size_t i;
- commit->parents[i] = git_revwalk__commit_lookup(walk, &oid);
- if (commit->parents[i] == NULL)
- return -1;
+ commit = git__calloc(1, sizeof(*commit));
+ GIT_ERROR_CHECK_ALLOC(commit);
+ commit->object.repo = walk->repo;
- buffer += parent_len;
+ if ((error = git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK)) < 0) {
+ git__free(commit);
+ return error;
}
- commit->out_degree = (unsigned short)parents;
-
- if ((committer_start = buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
- return commit_error(commit, "object is corrupted");
-
- buffer++;
-
- if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL)
- return commit_error(commit, "object is corrupted");
-
- /* Skip trailing spaces */
- while (buffer > committer_start && git__isspace(*buffer))
- buffer--;
-
- /* Seek for the beginning of the pack of digits */
- while (buffer > committer_start && git__isdigit(*buffer))
- buffer--;
-
- /* Skip potential timezone offset */
- if ((buffer > committer_start) && (*buffer == '+' || *buffer == '-')) {
- buffer--;
+ if (!git__is_uint16(git_array_size(commit->parent_ids))) {
+ git__free(commit);
+ git_error_set(GIT_ERROR_INVALID, "commit has more than 2^16 parents");
+ return -1;
+ }
- while (buffer > committer_start && git__isspace(*buffer))
- buffer--;
+ node->time = commit->committer->when.time;
+ node->out_degree = (uint16_t) git_array_size(commit->parent_ids);
+ node->parents = alloc_parents(walk, node, node->out_degree);
+ GIT_ERROR_CHECK_ALLOC(node->parents);
- while (buffer > committer_start && git__isdigit(*buffer))
- buffer--;
+ git_array_foreach(commit->parent_ids, i, parent_oid) {
+ node->parents[i] = git_revwalk__commit_lookup(walk, parent_oid);
}
- if ((buffer == committer_start) ||
- (git__strntol64(&commit_time, (char *)(buffer + 1),
- buffer_end - buffer + 1, NULL, 10) < 0))
- return commit_error(commit, "cannot parse commit time");
+ git_commit__free(commit);
+
+ node->parsed = 1;
- commit->time = commit_time;
- commit->parsed = 1;
return 0;
}
git_error_set(GIT_ERROR_INVALID, "object is no commit object");
error = -1;
} else
- error = commit_quick_parse(
- walk, commit,
- (const uint8_t *)git_odb_object_data(obj),
- git_odb_object_size(obj));
+ error = commit_quick_parse(walk, commit, obj);
git_odb_object_free(obj);
return error;
added:1,
flags : FLAG_BITS;
- unsigned short in_degree;
- unsigned short out_degree;
+ uint16_t in_degree;
+ uint16_t out_degree;
struct git_commit_list_node **parents;
} git_commit_list_node;
# include <ws2tcpip.h>
# include "win32/msvc-compat.h"
# include "win32/mingw-compat.h"
+# include "win32/w32_common.h"
# include "win32/win32-compat.h"
# include "win32/error.h"
# include "win32/version.h"
#include "git2/types.h"
#include "git2/errors.h"
+#include "errors.h"
#include "thread-utils.h"
#include "integer.h"
+#include "assert_safe.h"
/*
* Include the declarations for deprecated functions; this ensures
*/
#include "git2/deprecated.h"
-#include <regex.h>
+#include "posix.h"
#define DEFAULT_BUFSIZE 65536
#define FILEIO_BUFSIZE DEFAULT_BUFSIZE
#define GIT_ERROR_CHECK_ERROR(code) \
do { int _err = (code); if (_err) return _err; } while (0)
-/**
- * Set the error message for this thread, formatting as needed.
- */
-
-void git_error_set(int error_class, const char *string, ...) GIT_FORMAT_PRINTF(2, 3);
-
-/**
- * Set the error message for a regex failure, using the internal regex
- * error code lookup and return a libgit error code.
- */
-int git_error_set_regex(const regex_t *regex, int error_code);
-
-/**
- * Set error message for user callback if needed.
- *
- * If the error code in non-zero and no error message is set, this
- * sets a generic error message.
- *
- * @return This always returns the `error_code` parameter.
- */
-GIT_INLINE(int) git_error_set_after_callback_function(
- int error_code, const char *action)
-{
- if (error_code) {
- const git_error *e = git_error_last();
- if (!e || !e->message)
- git_error_set(e ? e->klass : GIT_ERROR_CALLBACK,
- "%s callback returned %d", action, error_code);
- }
- return error_code;
-}
-
-#ifdef GIT_WIN32
-#define git_error_set_after_callback(code) \
- git_error_set_after_callback_function((code), __FUNCTION__)
-#else
-#define git_error_set_after_callback(code) \
- git_error_set_after_callback_function((code), __func__)
-#endif
-
-/**
- * Gets the system error code for this thread.
- */
-int git_error_system_last(void);
-
-/**
- * Sets the system error code for this thread.
- */
-void git_error_system_set(int code);
-
-/**
- * Structure to preserve libgit2 error state
- */
-typedef struct {
- int error_code;
- unsigned int oom : 1;
- git_error error_msg;
-} git_error_state;
-
-/**
- * Capture current error state to restore later, returning error code.
- * If `error_code` is zero, this does not clear the current error state.
- * You must either restore this error state, or free it.
- */
-extern int git_error_state_capture(git_error_state *state, int error_code);
-
-/**
- * Restore error state to a previous value, returning saved error code.
- */
-extern int git_error_state_restore(git_error_state *state);
-
-/** Free an error state. */
-extern void git_error_state_free(git_error_state *state);
-
/**
* Check a versioned structure for validity
*/
#include "config.h"
-#include "sysdir.h"
#include "git2/config.h"
#include "git2/sys/config.h"
-#include "vector.h"
+
#include "buf_text.h"
#include "config_backend.h"
+#include "regexp.h"
+#include "sysdir.h"
#include "transaction.h"
+#include "vector.h"
#if GIT_WIN32
# include <windows.h>
#endif
git_config_iterator parent;
git_config_iterator *current;
const git_config *cfg;
- regex_t regex;
+ git_regexp regex;
size_t i;
} all_iter;
*/
while ((error = all_iter_next(entry, _iter)) == 0) {
/* skip non-matching keys if regexp was provided */
- if (regexec(&iter->regex, (*entry)->name, 0, NULL, 0) != 0)
+ if (git_regexp_match(&iter->regex, (*entry)->name) != 0)
continue;
/* and simply return if we like the entry's name */
{
all_iter *iter = (all_iter *) _iter;
- regfree(&iter->regex);
+ git_regexp_dispose(&iter->regex);
all_iter_free(_iter);
}
iter = git__calloc(1, sizeof(all_iter));
GIT_ERROR_CHECK_ALLOC(iter);
- if ((result = p_regcomp(&iter->regex, regexp, REG_EXTENDED)) != 0) {
- git_error_set_regex(&iter->regex, result);
+ if ((result = git_regexp_compile(&iter->regex, regexp, 0)) < 0) {
git__free(iter);
return -1;
}
{
git_config_entry *entry;
git_config_iterator* iter;
- regex_t regex;
+ git_regexp regex;
int error = 0;
assert(backend && cb);
- if (regexp != NULL) {
- if ((error = p_regcomp(®ex, regexp, REG_EXTENDED)) != 0) {
- git_error_set_regex(®ex, error);
- regfree(®ex);
- return -1;
- }
- }
+ if (regexp && git_regexp_compile(®ex, regexp, 0) < 0)
+ return -1;
if ((error = backend->iterator(&iter, backend)) < 0) {
iter = NULL;
while (!(iter->next(&entry, iter) < 0)) {
/* skip non-matching keys if regexp was provided */
- if (regexp && regexec(®ex, entry->name, 0, NULL, 0) != 0)
+ if (regexp && git_regexp_match(®ex, entry->name) != 0)
continue;
/* abort iterator on non-zero return value */
}
if (regexp != NULL)
- regfree(®ex);
+ git_regexp_dispose(®ex);
iter->free(iter);
error = backend->set(backend, name, value);
if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL)
- git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg));
+ git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(cfg));
return error;
}
int *out,
const git_config *cfg,
const char *name,
- const git_cvar_map *maps,
+ const git_configmap *maps,
size_t map_n)
{
git_config_entry *entry;
git_config_iterator parent;
git_config_iterator *iter;
char *name;
- regex_t regex;
+ git_regexp regex;
int have_regex;
} multivar_iter;
if (!iter->have_regex)
return 0;
- if (regexec(&iter->regex, (*entry)->value, 0, NULL, 0) == 0)
+ if (git_regexp_match(&iter->regex, (*entry)->value) == 0)
return 0;
}
return error;
}
-void multivar_iter_free(git_config_iterator *_iter)
+static void multivar_iter_free(git_config_iterator *_iter)
{
multivar_iter *iter = (multivar_iter *) _iter;
git__free(iter->name);
if (iter->have_regex)
- regfree(&iter->regex);
+ git_regexp_dispose(&iter->regex);
git__free(iter);
}
goto on_error;
if (regexp != NULL) {
- error = p_regcomp(&iter->regex, regexp, REG_EXTENDED);
- if (error != 0) {
- git_error_set_regex(&iter->regex, error);
- error = -1;
- regfree(&iter->regex);
+ if ((error = git_regexp_compile(&iter->regex, regexp, 0)) < 0)
goto on_error;
- }
iter->have_regex = 1;
}
int git_config_lookup_map_value(
int *out,
- const git_cvar_map *maps,
+ const git_configmap *maps,
size_t map_n,
const char *value)
{
size_t i;
- if (!value)
- goto fail_parse;
-
for (i = 0; i < map_n; ++i) {
- const git_cvar_map *m = maps + i;
+ const git_configmap *m = maps + i;
- switch (m->cvar_type) {
- case GIT_CVAR_FALSE:
- case GIT_CVAR_TRUE: {
+ switch (m->type) {
+ case GIT_CONFIGMAP_FALSE:
+ case GIT_CONFIGMAP_TRUE: {
int bool_val;
- if (git__parse_bool(&bool_val, value) == 0 &&
- bool_val == (int)m->cvar_type) {
+ if (git_config_parse_bool(&bool_val, value) == 0 &&
+ bool_val == (int)m->type) {
*out = m->map_value;
return 0;
}
break;
}
- case GIT_CVAR_INT32:
+ case GIT_CONFIGMAP_INT32:
if (git_config_parse_int32(out, value) == 0)
return 0;
break;
- case GIT_CVAR_STRING:
- if (strcasecmp(value, m->str_match) == 0) {
+ case GIT_CONFIGMAP_STRING:
+ if (value && strcasecmp(value, m->str_match) == 0) {
*out = m->map_value;
return 0;
}
}
}
-fail_parse:
git_error_set(GIT_ERROR_CONFIG, "failed to map '%s'", value);
return -1;
}
-int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
- const git_cvar_map *maps, size_t map_n, int enum_val)
+int git_config_lookup_map_enum(git_configmap_t *type_out, const char **str_out,
+ const git_configmap *maps, size_t map_n, int enum_val)
{
size_t i;
for (i = 0; i < map_n; i++) {
- const git_cvar_map *m = &maps[i];
+ const git_configmap *m = &maps[i];
if (m->map_value != enum_val)
continue;
- *type_out = m->cvar_type;
+ *type_out = m->type;
*str_out = m->str_match;
return 0;
}
extern int git_config__get_int_force(
const git_config *cfg, const char *key, int fallback_value);
-/* API for repository cvar-style lookups from config - not cached, but
- * uses cvar value maps and fallbacks
+/* API for repository configmap-style lookups from config - not cached, but
+ * uses configmap value maps and fallbacks
*/
-extern int git_config__cvar(
- int *out, git_config *config, git_cvar_cached cvar);
+extern int git_config__configmap_lookup(
+ int *out, git_config *config, git_configmap_item item);
/**
* The opposite of git_config_lookup_map_value, we take an enum value
* and map it to the string or bool value on the config.
*/
-int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
- const git_cvar_map *maps, size_t map_n, int enum_val);
+int git_config_lookup_map_enum(git_configmap_t *type_out,
+ const char **str_out, const git_configmap *maps,
+ size_t map_n, int enum_val);
/**
* Unlock the backend with the highest priority
*/
extern int git_config_backend_from_file(git_config_backend **out, const char *path);
+/**
+ * Create a readonly configuration file backend from another backend
+ *
+ * This copies the complete contents of the source backend to the
+ * new backend. The new backend will be completely read-only and
+ * cannot be modified.
+ *
+ * @param out the new snapshotted backend
+ * @param source the backend to copy
+ */
+extern int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source);
+
/**
* Create an in-memory configuration file backend
*
#include "common.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
#include "config.h"
#include "git2/config.h"
#include "filter.h"
struct map_data {
- const char *cvar_name;
- git_cvar_map *maps;
+ const char *name;
+ git_configmap *maps;
size_t map_count;
int default_value;
};
* value is native. See gitattributes(5) for more information on
* end-of-line conversion.
*/
-static git_cvar_map _cvar_map_eol[] = {
- {GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET},
- {GIT_CVAR_STRING, "lf", GIT_EOL_LF},
- {GIT_CVAR_STRING, "crlf", GIT_EOL_CRLF},
- {GIT_CVAR_STRING, "native", GIT_EOL_NATIVE}
+static git_configmap _configmap_eol[] = {
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_EOL_UNSET},
+ {GIT_CONFIGMAP_STRING, "lf", GIT_EOL_LF},
+ {GIT_CONFIGMAP_STRING, "crlf", GIT_EOL_CRLF},
+ {GIT_CONFIGMAP_STRING, "native", GIT_EOL_NATIVE}
};
/*
* does not have normalized line endings. This variable can be set to input,
* in which case no output conversion is performed.
*/
-static git_cvar_map _cvar_map_autocrlf[] = {
- {GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
- {GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
- {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT}
+static git_configmap _configmap_autocrlf[] = {
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
+ {GIT_CONFIGMAP_STRING, "input", GIT_AUTO_CRLF_INPUT}
};
-static git_cvar_map _cvar_map_safecrlf[] = {
- {GIT_CVAR_FALSE, NULL, GIT_SAFE_CRLF_FALSE},
- {GIT_CVAR_TRUE, NULL, GIT_SAFE_CRLF_FAIL},
- {GIT_CVAR_STRING, "warn", GIT_SAFE_CRLF_WARN}
+static git_configmap _configmap_safecrlf[] = {
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SAFE_CRLF_FALSE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SAFE_CRLF_FAIL},
+ {GIT_CONFIGMAP_STRING, "warn", GIT_SAFE_CRLF_WARN}
};
-static git_cvar_map _cvar_map_logallrefupdates[] = {
- {GIT_CVAR_FALSE, NULL, GIT_LOGALLREFUPDATES_FALSE},
- {GIT_CVAR_TRUE, NULL, GIT_LOGALLREFUPDATES_TRUE},
- {GIT_CVAR_STRING, "always", GIT_LOGALLREFUPDATES_ALWAYS},
+static git_configmap _configmap_logallrefupdates[] = {
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_LOGALLREFUPDATES_FALSE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_LOGALLREFUPDATES_TRUE},
+ {GIT_CONFIGMAP_STRING, "always", GIT_LOGALLREFUPDATES_ALWAYS},
};
/*
* Generic map for integer values
*/
-static git_cvar_map _cvar_map_int[] = {
- {GIT_CVAR_INT32, NULL, 0},
+static git_configmap _configmap_int[] = {
+ {GIT_CONFIGMAP_INT32, NULL, 0},
};
-static struct map_data _cvar_maps[] = {
- {"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT},
- {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT},
+static struct map_data _configmaps[] = {
+ {"core.autocrlf", _configmap_autocrlf, ARRAY_SIZE(_configmap_autocrlf), GIT_AUTO_CRLF_DEFAULT},
+ {"core.eol", _configmap_eol, ARRAY_SIZE(_configmap_eol), GIT_EOL_DEFAULT},
{"core.symlinks", NULL, 0, GIT_SYMLINKS_DEFAULT },
{"core.ignorecase", NULL, 0, GIT_IGNORECASE_DEFAULT },
{"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT },
{"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT },
{"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT },
- {"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT },
+ {"core.abbrev", _configmap_int, 1, GIT_ABBREV_DEFAULT },
{"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT },
- {"core.safecrlf", _cvar_map_safecrlf, ARRAY_SIZE(_cvar_map_safecrlf), GIT_SAFE_CRLF_DEFAULT},
- {"core.logallrefupdates", _cvar_map_logallrefupdates, ARRAY_SIZE(_cvar_map_logallrefupdates), GIT_LOGALLREFUPDATES_DEFAULT},
+ {"core.safecrlf", _configmap_safecrlf, ARRAY_SIZE(_configmap_safecrlf), GIT_SAFE_CRLF_DEFAULT},
+ {"core.logallrefupdates", _configmap_logallrefupdates, ARRAY_SIZE(_configmap_logallrefupdates), GIT_LOGALLREFUPDATES_DEFAULT},
{"core.protecthfs", NULL, 0, GIT_PROTECTHFS_DEFAULT },
{"core.protectntfs", NULL, 0, GIT_PROTECTNTFS_DEFAULT },
{"core.fsyncobjectfiles", NULL, 0, GIT_FSYNCOBJECTFILES_DEFAULT },
};
-int git_config__cvar(int *out, git_config *config, git_cvar_cached cvar)
+int git_config__configmap_lookup(int *out, git_config *config, git_configmap_item item)
{
int error = 0;
- struct map_data *data = &_cvar_maps[(int)cvar];
+ struct map_data *data = &_configmaps[(int)item];
git_config_entry *entry;
- if ((error = git_config__lookup_entry(&entry, config, data->cvar_name, false)) < 0)
+ if ((error = git_config__lookup_entry(&entry, config, data->name, false)) < 0)
return error;
if (!entry)
return error;
}
-int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
+int git_repository__configmap_lookup(int *out, git_repository *repo, git_configmap_item item)
{
- *out = repo->cvar_cache[(int)cvar];
+ *out = repo->configmap_cache[(int)item];
- if (*out == GIT_CVAR_NOT_CACHED) {
+ if (*out == GIT_CONFIGMAP_NOT_CACHED) {
int error;
git_config *config;
if ((error = git_repository_config__weakptr(&config, repo)) < 0 ||
- (error = git_config__cvar(out, config, cvar)) < 0)
+ (error = git_config__configmap_lookup(out, config, item)) < 0)
return error;
- repo->cvar_cache[(int)cvar] = *out;
+ repo->configmap_cache[(int)item] = *out;
}
return 0;
}
-void git_repository__cvar_cache_clear(git_repository *repo)
+void git_repository__configmap_lookup_cache_clear(git_repository *repo)
{
int i;
- for (i = 0; i < GIT_CVAR_CACHE_MAX; ++i)
- repo->cvar_cache[i] = GIT_CVAR_NOT_CACHED;
+ for (i = 0; i < GIT_CONFIGMAP_CACHE_MAX; ++i)
+ repo->configmap_cache[i] = GIT_CONFIGMAP_NOT_CACHED;
}
git_config_entry *entry;
} config_entry_list;
+typedef struct {
+ git_config_entry *entry;
+ bool multivar;
+} config_entry_map_head;
+
typedef struct config_entries_iterator {
git_config_iterator parent;
git_config_entries *entries;
config_entry_list *list;
};
-static void config_entry_list_free(config_entry_list *list)
-{
- config_entry_list *next;
-
- while (list != NULL) {
- next = list->next;
-
- git__free((char*) list->entry->name);
- git__free((char *) list->entry->value);
- git__free(list->entry);
- git__free(list);
-
- list = next;
- };
-}
-
-static void config_entry_list_append(config_entry_list **list, config_entry_list *entry)
-{
- if (*list)
- (*list)->last->next = entry;
- else
- *list = entry;
- (*list)->last = entry;
-}
-
int git_config_entries_new(git_config_entries **out)
{
git_config_entries *entries;
GIT_ERROR_CHECK_ALLOC(entries);
GIT_REFCOUNT_INC(entries);
- if ((error = git_strmap_alloc(&entries->map)) < 0)
+ if ((error = git_strmap_new(&entries->map)) < 0)
git__free(entries);
else
*out = entries;
return error;
}
+int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry)
+{
+ git_config_entry *duplicated;
+ int error;
+
+ duplicated = git__calloc(1, sizeof(git_config_entry));
+ GIT_ERROR_CHECK_ALLOC(duplicated);
+
+ duplicated->name = git__strdup(entry->name);
+ GIT_ERROR_CHECK_ALLOC(duplicated->name);
+
+ if (entry->value) {
+ duplicated->value = git__strdup(entry->value);
+ GIT_ERROR_CHECK_ALLOC(duplicated->value);
+ }
+ duplicated->level = entry->level;
+ duplicated->include_depth = entry->include_depth;
+
+ if ((error = git_config_entries_append(entries, duplicated)) < 0)
+ goto out;
+
+out:
+ if (error && duplicated) {
+ git__free((char *) duplicated->name);
+ git__free((char *) duplicated->value);
+ git__free(duplicated);
+ }
+ return error;
+}
+
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
{
git_config_entries *result = NULL;
if ((error = git_config_entries_new(&result)) < 0)
goto out;
- for (head = entries->list; head; head = head->next) {
- git_config_entry *dup;
-
- dup = git__calloc(1, sizeof(git_config_entry));
- dup->name = git__strdup(head->entry->name);
- GIT_ERROR_CHECK_ALLOC(dup->name);
- if (head->entry->value) {
- dup->value = git__strdup(head->entry->value);
- GIT_ERROR_CHECK_ALLOC(dup->value);
- }
- dup->level = head->entry->level;
- dup->include_depth = head->entry->include_depth;
-
- if ((error = git_config_entries_append(result, dup)) < 0)
+ for (head = entries->list; head; head = head->next)
+ if ((git_config_entries_dup_entry(result, head->entry)) < 0)
goto out;
- }
*out = result;
result = NULL;
static void config_entries_free(git_config_entries *entries)
{
config_entry_list *list = NULL, *next;
+ config_entry_map_head *head;
- git_strmap_foreach_value(entries->map, list, config_entry_list_free(list));
+ git_strmap_foreach_value(entries->map, head,
+ git__free((char *) head->entry->name); git__free(head)
+ );
git_strmap_free(entries->map);
list = entries->list;
while (list != NULL) {
next = list->next;
+ git__free((char *) list->entry->value);
+ git__free(list->entry);
git__free(list);
list = next;
}
int git_config_entries_append(git_config_entries *entries, git_config_entry *entry)
{
- config_entry_list *existing, *var;
- int error = 0;
- size_t pos;
+ config_entry_list *list_head;
+ config_entry_map_head *map_head;
- var = git__calloc(1, sizeof(config_entry_list));
- GIT_ERROR_CHECK_ALLOC(var);
- var->entry = entry;
-
- pos = git_strmap_lookup_index(entries->map, entry->name);
- if (!git_strmap_valid_index(entries->map, pos)) {
+ if ((map_head = git_strmap_get(entries->map, entry->name)) != NULL) {
+ map_head->multivar = true;
/*
- * We only ever inspect `last` from the first config
- * entry in a multivar. In case where this new entry is
- * the first one in the entry map, it will also be the
- * last one at the time of adding it, which is
- * why we set `last` here to itself. Otherwise we
- * do not have to set `last` and leave it set to
- * `NULL`.
+ * This is a micro-optimization for configuration files
+ * with a lot of same keys. As for multivars the entry's
+ * key will be the same for all entries, we can just free
+ * all except the first entry's name and just re-use it.
*/
- var->last = var;
-
- git_strmap_insert(entries->map, entry->name, var, &error);
-
- if (error > 0)
- error = 0;
+ git__free((char *) entry->name);
+ entry->name = map_head->entry->name;
} else {
- existing = git_strmap_value_at(entries->map, pos);
- config_entry_list_append(&existing, var);
+ map_head = git__calloc(1, sizeof(*map_head));
+ if ((git_strmap_set(entries->map, entry->name, map_head)) < 0)
+ return -1;
}
+ map_head->entry = entry;
- var = git__calloc(1, sizeof(config_entry_list));
- GIT_ERROR_CHECK_ALLOC(var);
- var->entry = entry;
- config_entry_list_append(&entries->list, var);
-
- return error;
-}
-
-int config_entry_get(config_entry_list **out, git_config_entries *entries, const char *key)
-{
- size_t pos;
-
- pos = git_strmap_lookup_index(entries->map, key);
+ list_head = git__calloc(1, sizeof(config_entry_list));
+ GIT_ERROR_CHECK_ALLOC(list_head);
+ list_head->entry = entry;
- /* no error message; the config system will write one */
- if (!git_strmap_valid_index(entries->map, pos))
- return GIT_ENOTFOUND;
-
- *out = git_strmap_value_at(entries->map, pos);
+ if (entries->list)
+ entries->list->last->next = list_head;
+ else
+ entries->list = list_head;
+ entries->list->last = list_head;
return 0;
}
int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key)
{
- config_entry_list *entry;
- int error;
-
- if ((error = config_entry_get(&entry, entries, key)) < 0)
- return error;
- *out = entry->last->entry;
-
+ config_entry_map_head *entry;
+ if ((entry = git_strmap_get(entries->map, key)) == NULL)
+ return GIT_ENOTFOUND;
+ *out = entry->entry;
return 0;
}
int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key)
{
- config_entry_list *entry;
- int error;
+ config_entry_map_head *entry;
- if ((error = config_entry_get(&entry, entries, key)) < 0)
- return error;
+ if ((entry = git_strmap_get(entries->map, key)) == NULL)
+ return GIT_ENOTFOUND;
- if (entry->next != NULL) {
+ if (entry->multivar) {
git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being a multivar");
return -1;
}
return 0;
}
-void config_iterator_free(git_config_iterator *iter)
+static void config_iterator_free(git_config_iterator *iter)
{
config_entries_iterator *it = (config_entries_iterator *) iter;
git_config_entries_free(it->entries);
git__free(it);
}
-int config_iterator_next(
+static int config_iterator_next(
git_config_entry **entry,
git_config_iterator *iter)
{
int git_config_entries_new(git_config_entries **out);
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries);
+int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry);
void git_config_entries_incref(git_config_entries *entries);
void git_config_entries_free(git_config_entries *entries);
/* Add or append the new config option */
#include "config.h"
-#include "filebuf.h"
-#include "sysdir.h"
-#include "buffer.h"
-#include "buf_text.h"
#include "git2/config.h"
#include "git2/sys/config.h"
-#include "git2/types.h"
-#include "strmap.h"
+
#include "array.h"
-#include "config_parse.h"
+#include "buffer.h"
+#include "config_backend.h"
#include "config_entries.h"
-
-#include <ctype.h>
-#include <sys/types.h>
-#include <regex.h>
+#include "config_parse.h"
+#include "filebuf.h"
+#include "regexp.h"
+#include "sysdir.h"
+#include "wildmatch.h"
/* Max depth for [include] directives */
#define MAX_INCLUDE_DEPTH 10
+typedef struct config_file {
+ git_futils_filestamp stamp;
+ git_oid checksum;
+ char *path;
+ git_array_t(struct config_file) includes;
+} config_file;
+
typedef struct {
git_config_backend parent;
- /* mutex to coordinate accessing the values */
git_mutex values_mutex;
git_config_entries *entries;
const git_repository *repo;
git_config_level_t level;
-} diskfile_header;
-
-typedef struct {
- diskfile_header header;
git_array_t(git_config_parser) readers;
git_filebuf locked_buf;
git_buf locked_content;
- struct config_file file;
-} diskfile_backend;
-
-typedef struct {
- diskfile_header header;
-
- diskfile_backend *snapshot_from;
-} diskfile_readonly_backend;
+ config_file file;
+} config_file_backend;
typedef struct {
const git_repository *repo;
- const char *file_path;
+ config_file *file;
git_config_entries *entries;
git_config_level_t level;
unsigned int depth;
-} diskfile_parse_state;
+} config_file_parse_data;
-static int config_read(git_config_entries *entries, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth);
-static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char *value);
+static int config_file_read(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth);
+static int config_file_read_buffer(git_config_entries *entries, const git_repository *repo, config_file *file, git_config_level_t level, int depth, const char *buf, size_t buflen);
+static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char *value);
static char *escape_value(const char *ptr);
-static int config_snapshot(git_config_backend **out, git_config_backend *in);
-
-static int config_error_readonly(void)
-{
- git_error_set(GIT_ERROR_CONFIG, "this backend is read-only");
- return -1;
-}
-
/**
* Take the current values map from the backend and increase its
* refcount. This is its own function to make sure we use the mutex to
* avoid the map pointer from changing under us.
*/
-static git_config_entries *diskfile_entries_take(diskfile_header *h)
+static int config_file_entries_take(git_config_entries **out, config_file_backend *b)
{
- git_config_entries *entries;
+ int error;
- if (git_mutex_lock(&h->values_mutex) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to lock config backend");
- return NULL;
+ if ((error = git_mutex_lock(&b->values_mutex)) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to lock config backend");
+ return error;
}
- entries = h->entries;
- git_config_entries_incref(entries);
+ git_config_entries_incref(b->entries);
+ *out = b->entries;
- git_mutex_unlock(&h->values_mutex);
+ git_mutex_unlock(&b->values_mutex);
- return entries;
+ return 0;
}
-static void config_file_clear(struct config_file *file)
+static void config_file_clear(config_file *file)
{
- struct config_file *include;
+ config_file *include;
uint32_t i;
if (file == NULL)
git__free(file->path);
}
-static int config_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo)
+static int config_file_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo)
{
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
int res;
- diskfile_backend *b = (diskfile_backend *)cfg;
- b->header.level = level;
- b->header.repo = repo;
+ b->level = level;
+ b->repo = repo;
- if ((res = git_config_entries_new(&b->header.entries)) < 0)
+ if ((res = git_config_entries_new(&b->entries)) < 0)
return res;
if (!git_path_exists(b->file.path))
return 0;
- if (res < 0 || (res = config_read(b->header.entries, repo, &b->file, level, 0)) < 0) {
- git_config_entries_free(b->header.entries);
- b->header.entries = NULL;
+ /*
+ * git silently ignores configuration files that are not
+ * readable. We emulate that behavior. This is particularly
+ * important for sandboxed applications on macOS where the
+ * git configuration files may not be readable.
+ */
+ if (p_access(b->file.path, R_OK) < 0)
+ return GIT_ENOTFOUND;
+
+ if (res < 0 || (res = config_file_read(b->entries, repo, &b->file, level, 0)) < 0) {
+ git_config_entries_free(b->entries);
+ b->entries = NULL;
}
return res;
}
-static int config_is_modified(int *modified, struct config_file *file)
+static int config_file_is_modified(int *modified, config_file *file)
{
- git_config_file *include;
+ config_file *include;
git_buf buf = GIT_BUF_INIT;
git_oid hash;
uint32_t i;
*modified = 0;
+ if (!git_futils_filestamp_check(&file->stamp, file->path))
+ goto check_includes;
+
if ((error = git_futils_readbuffer(&buf, file->path)) < 0)
goto out;
goto out;
}
+check_includes:
git_array_foreach(file->includes, i, include) {
- if ((error = config_is_modified(modified, include)) < 0 || *modified)
+ if ((error = config_file_is_modified(modified, include)) < 0 || *modified)
goto out;
}
return error;
}
-static int config_refresh(git_config_backend *cfg)
+static int config_file_set_entries(git_config_backend *cfg, git_config_entries *entries)
{
- diskfile_backend *b = (diskfile_backend *)cfg;
- git_config_entries *entries = NULL, *tmp;
- git_config_file *include;
- int error, modified;
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
+ git_config_entries *old = NULL;
+ config_file *include;
+ int error;
uint32_t i;
- if (b->header.parent.readonly)
- return config_error_readonly();
+ if (b->parent.readonly) {
+ git_error_set(GIT_ERROR_CONFIG, "this backend is read-only");
+ return -1;
+ }
- error = config_is_modified(&modified, &b->file);
- if (error < 0 && error != GIT_ENOTFOUND)
+ git_array_foreach(b->file.includes, i, include)
+ config_file_clear(include);
+ git_array_clear(b->file.includes);
+
+ if ((error = git_mutex_lock(&b->values_mutex)) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to lock config backend");
goto out;
+ }
- if (!modified)
- return 0;
+ old = b->entries;
+ b->entries = entries;
- if ((error = git_config_entries_new(&entries)) < 0)
- goto out;
+ git_mutex_unlock(&b->values_mutex);
- /* Reparse the current configuration */
- git_array_foreach(b->file.includes, i, include) {
- config_file_clear(include);
- }
- git_array_clear(b->file.includes);
+out:
+ git_config_entries_free(old);
+ return error;
+}
+
+static int config_file_refresh_from_buffer(git_config_backend *cfg, const char *buf, size_t buflen)
+{
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
+ git_config_entries *entries = NULL;
+ int error;
- if ((error = config_read(entries, b->header.repo, &b->file, b->header.level, 0)) < 0)
+ if ((error = git_config_entries_new(&entries)) < 0 ||
+ (error = config_file_read_buffer(entries, b->repo, &b->file,
+ b->level, 0, buf, buflen)) < 0 ||
+ (error = config_file_set_entries(cfg, entries)) < 0)
goto out;
- if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to lock config backend");
+ entries = NULL;
+out:
+ git_config_entries_free(entries);
+ return error;
+}
+
+static int config_file_refresh(git_config_backend *cfg)
+{
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
+ git_config_entries *entries = NULL;
+ int error, modified;
+
+ if (cfg->readonly)
+ return 0;
+
+ if ((error = config_file_is_modified(&modified, &b->file)) < 0 && error != GIT_ENOTFOUND)
goto out;
- }
- tmp = b->header.entries;
- b->header.entries = entries;
- entries = tmp;
+ if (!modified)
+ return 0;
- git_mutex_unlock(&b->header.values_mutex);
+ if ((error = git_config_entries_new(&entries)) < 0 ||
+ (error = config_file_read(entries, b->repo, &b->file, b->level, 0)) < 0 ||
+ (error = config_file_set_entries(cfg, entries)) < 0)
+ goto out;
+ entries = NULL;
out:
git_config_entries_free(entries);
return (error == GIT_ENOTFOUND) ? 0 : error;
}
-static void backend_free(git_config_backend *_backend)
+static void config_file_free(git_config_backend *_backend)
{
- diskfile_backend *backend = (diskfile_backend *)_backend;
+ config_file_backend *backend = GIT_CONTAINER_OF(_backend, config_file_backend, parent);
if (backend == NULL)
return;
config_file_clear(&backend->file);
- git_config_entries_free(backend->header.entries);
- git_mutex_free(&backend->header.values_mutex);
+ git_config_entries_free(backend->entries);
+ git_mutex_free(&backend->values_mutex);
git__free(backend);
}
-static int config_iterator_new(
+static int config_file_iterator(
git_config_iterator **iter,
- struct git_config_backend* backend)
+ struct git_config_backend *backend)
{
- diskfile_header *bh = (diskfile_header *) backend;
- git_config_entries *entries;
+ config_file_backend *b = GIT_CONTAINER_OF(backend, config_file_backend, parent);
+ git_config_entries *dupped = NULL, *entries = NULL;
int error;
- if ((error = git_config_entries_dup(&entries, bh->entries)) < 0)
- return error;
-
- if ((error = git_config_entries_iterator_new(iter, entries)) < 0)
+ if ((error = config_file_refresh(backend)) < 0 ||
+ (error = config_file_entries_take(&entries, b)) < 0 ||
+ (error = git_config_entries_dup(&dupped, entries)) < 0 ||
+ (error = git_config_entries_iterator_new(iter, dupped)) < 0)
goto out;
out:
/* Let iterator delete duplicated entries when it's done */
git_config_entries_free(entries);
+ git_config_entries_free(dupped);
return error;
}
-static int config_set(git_config_backend *cfg, const char *name, const char *value)
+static int config_file_snapshot(git_config_backend **out, git_config_backend *backend)
{
- diskfile_backend *b = (diskfile_backend *)cfg;
+ return git_config_backend_snapshot(out, backend);
+}
+
+static int config_file_set(git_config_backend *cfg, const char *name, const char *value)
+{
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
git_config_entries *entries;
git_config_entry *existing;
char *key, *esc_value = NULL;
if ((error = git_config__normalize_name(name, &key)) < 0)
return error;
- if ((entries = diskfile_entries_take(&b->header)) == NULL)
- return -1;
+ if ((error = config_file_entries_take(&entries, b)) < 0)
+ return error;
/* Check whether we'd be modifying an included or multivar key */
if ((error = git_config_entries_get_unique(&existing, entries, key)) < 0) {
GIT_ERROR_CHECK_ALLOC(esc_value);
}
- if ((error = config_write(b, name, key, NULL, esc_value)) < 0)
+ if ((error = config_file_write(b, name, key, NULL, esc_value)) < 0)
goto out;
- error = config_refresh(cfg);
-
out:
git_config_entries_free(entries);
git__free(esc_value);
}
/* release the map containing the entry as an equivalent to freeing it */
-static void free_diskfile_entry(git_config_entry *entry)
+static void config_file_entry_free(git_config_entry *entry)
{
git_config_entries *entries = (git_config_entries *) entry->payload;
git_config_entries_free(entries);
/*
* Internal function that actually gets the value in string form
*/
-static int config_get(git_config_backend *cfg, const char *key, git_config_entry **out)
+static int config_file_get(git_config_backend *cfg, const char *key, git_config_entry **out)
{
- diskfile_header *h = (diskfile_header *)cfg;
+ config_file_backend *h = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
git_config_entries *entries = NULL;
git_config_entry *entry;
int error = 0;
- if (!h->parent.readonly && ((error = config_refresh(cfg)) < 0))
+ if (!h->parent.readonly && ((error = config_file_refresh(cfg)) < 0))
return error;
- if ((entries = diskfile_entries_take(h)) == NULL)
- return -1;
+ if ((error = config_file_entries_take(&entries, h)) < 0)
+ return error;
if ((error = (git_config_entries_get(&entry, entries, key))) < 0) {
git_config_entries_free(entries);
return error;
}
- entry->free = free_diskfile_entry;
+ entry->free = config_file_entry_free;
entry->payload = entries;
*out = entry;
return 0;
}
-static int config_set_multivar(
+static int config_file_set_multivar(
git_config_backend *cfg, const char *name, const char *regexp, const char *value)
{
- diskfile_backend *b = (diskfile_backend *)cfg;
- char *key;
- regex_t preg;
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
+ git_regexp preg;
int result;
+ char *key;
assert(regexp);
if ((result = git_config__normalize_name(name, &key)) < 0)
return result;
- result = p_regcomp(&preg, regexp, REG_EXTENDED);
- if (result != 0) {
- git_error_set_regex(&preg, result);
- result = -1;
+ if ((result = git_regexp_compile(&preg, regexp, 0)) < 0)
goto out;
- }
- /* If we do have it, set call config_write() and reload */
- if ((result = config_write(b, name, key, &preg, value)) < 0)
+ /* If we do have it, set call config_file_write() and reload */
+ if ((result = config_file_write(b, name, key, &preg, value)) < 0)
goto out;
- result = config_refresh(cfg);
-
out:
git__free(key);
- regfree(&preg);
+ git_regexp_dispose(&preg);
return result;
}
-static int config_delete(git_config_backend *cfg, const char *name)
+static int config_file_delete(git_config_backend *cfg, const char *name)
{
- diskfile_backend *b = (diskfile_backend *)cfg;
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
git_config_entries *entries = NULL;
git_config_entry *entry;
char *key = NULL;
if ((error = git_config__normalize_name(name, &key)) < 0)
goto out;
- if ((entries = diskfile_entries_take(&b->header)) == NULL)
+ if ((error = config_file_entries_take(&entries, b)) < 0)
goto out;
/* Check whether we'd be modifying an included or multivar key */
goto out;
}
- if ((error = config_write(b, name, entry->name, NULL, NULL)) < 0)
- goto out;
-
- if ((error = config_refresh(cfg)) < 0)
+ if ((error = config_file_write(b, name, entry->name, NULL, NULL)) < 0)
goto out;
out:
return error;
}
-static int config_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp)
+static int config_file_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp)
{
- diskfile_backend *b = (diskfile_backend *)cfg;
+ config_file_backend *b = GIT_CONTAINER_OF(cfg, config_file_backend, parent);
git_config_entries *entries = NULL;
git_config_entry *entry = NULL;
- regex_t preg = { 0 };
+ git_regexp preg = GIT_REGEX_INIT;
char *key = NULL;
int result;
if ((result = git_config__normalize_name(name, &key)) < 0)
goto out;
- if ((entries = diskfile_entries_take(&b->header)) == NULL) {
- result = -1;
+ if ((result = config_file_entries_take(&entries, b)) < 0)
goto out;
- }
if ((result = git_config_entries_get(&entry, entries, key)) < 0) {
if (result == GIT_ENOTFOUND)
goto out;
}
- if ((result = p_regcomp(&preg, regexp, REG_EXTENDED)) != 0) {
- git_error_set_regex(&preg, result);
- result = -1;
+ if ((result = git_regexp_compile(&preg, regexp, 0)) < 0)
goto out;
- }
- if ((result = config_write(b, name, key, &preg, NULL)) < 0)
- goto out;
-
- if ((result = config_refresh(cfg)) < 0)
+ if ((result = config_file_write(b, name, key, &preg, NULL)) < 0)
goto out;
out:
git_config_entries_free(entries);
git__free(key);
- regfree(&preg);
+ git_regexp_dispose(&preg);
return result;
}
-static int config_lock(git_config_backend *_cfg)
+static int config_file_lock(git_config_backend *_cfg)
{
- diskfile_backend *cfg = (diskfile_backend *) _cfg;
+ config_file_backend *cfg = GIT_CONTAINER_OF(_cfg, config_file_backend, parent);
int error;
if ((error = git_filebuf_open(&cfg->locked_buf, cfg->file.path, 0, GIT_CONFIG_FILE_MODE)) < 0)
}
-static int config_unlock(git_config_backend *_cfg, int success)
+static int config_file_unlock(git_config_backend *_cfg, int success)
{
- diskfile_backend *cfg = (diskfile_backend *) _cfg;
+ config_file_backend *cfg = GIT_CONTAINER_OF(_cfg, config_file_backend, parent);
int error = 0;
if (success) {
int git_config_backend_from_file(git_config_backend **out, const char *path)
{
- diskfile_backend *backend;
+ config_file_backend *backend;
- backend = git__calloc(1, sizeof(diskfile_backend));
+ backend = git__calloc(1, sizeof(config_file_backend));
GIT_ERROR_CHECK_ALLOC(backend);
- backend->header.parent.version = GIT_CONFIG_BACKEND_VERSION;
- git_mutex_init(&backend->header.values_mutex);
+ backend->parent.version = GIT_CONFIG_BACKEND_VERSION;
+ git_mutex_init(&backend->values_mutex);
backend->file.path = git__strdup(path);
GIT_ERROR_CHECK_ALLOC(backend->file.path);
git_array_init(backend->file.includes);
- backend->header.parent.open = config_open;
- backend->header.parent.get = config_get;
- backend->header.parent.set = config_set;
- backend->header.parent.set_multivar = config_set_multivar;
- backend->header.parent.del = config_delete;
- backend->header.parent.del_multivar = config_delete_multivar;
- backend->header.parent.iterator = config_iterator_new;
- backend->header.parent.snapshot = config_snapshot;
- backend->header.parent.lock = config_lock;
- backend->header.parent.unlock = config_unlock;
- backend->header.parent.free = backend_free;
-
- *out = (git_config_backend *)backend;
-
- return 0;
-}
-
-static int config_set_readonly(git_config_backend *cfg, const char *name, const char *value)
-{
- GIT_UNUSED(cfg);
- GIT_UNUSED(name);
- GIT_UNUSED(value);
-
- return config_error_readonly();
-}
-
-static int config_set_multivar_readonly(
- git_config_backend *cfg, const char *name, const char *regexp, const char *value)
-{
- GIT_UNUSED(cfg);
- GIT_UNUSED(name);
- GIT_UNUSED(regexp);
- GIT_UNUSED(value);
-
- return config_error_readonly();
-}
-
-static int config_delete_multivar_readonly(git_config_backend *cfg, const char *name, const char *regexp)
-{
- GIT_UNUSED(cfg);
- GIT_UNUSED(name);
- GIT_UNUSED(regexp);
-
- return config_error_readonly();
-}
-
-static int config_delete_readonly(git_config_backend *cfg, const char *name)
-{
- GIT_UNUSED(cfg);
- GIT_UNUSED(name);
-
- return config_error_readonly();
-}
-
-static int config_lock_readonly(git_config_backend *_cfg)
-{
- GIT_UNUSED(_cfg);
-
- return config_error_readonly();
-}
-
-static int config_unlock_readonly(git_config_backend *_cfg, int success)
-{
- GIT_UNUSED(_cfg);
- GIT_UNUSED(success);
-
- return config_error_readonly();
-}
-
-static void backend_readonly_free(git_config_backend *_backend)
-{
- diskfile_backend *backend = (diskfile_backend *)_backend;
-
- if (backend == NULL)
- return;
-
- git_config_entries_free(backend->header.entries);
- git_mutex_free(&backend->header.values_mutex);
- git__free(backend);
-}
-
-static int config_readonly_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo)
-{
- diskfile_readonly_backend *b = (diskfile_readonly_backend *) cfg;
- diskfile_backend *src = b->snapshot_from;
- diskfile_header *src_header = &src->header;
- git_config_entries *entries;
- int error;
-
- if (!src_header->parent.readonly && (error = config_refresh(&src_header->parent)) < 0)
- return error;
-
- /* We're just copying data, don't care about the level or repo*/
- GIT_UNUSED(level);
- GIT_UNUSED(repo);
-
- if ((entries = diskfile_entries_take(src_header)) == NULL)
- return -1;
- b->header.entries = entries;
-
- return 0;
-}
-
-static int config_snapshot(git_config_backend **out, git_config_backend *in)
-{
- diskfile_readonly_backend *backend;
-
- backend = git__calloc(1, sizeof(diskfile_readonly_backend));
- GIT_ERROR_CHECK_ALLOC(backend);
-
- backend->header.parent.version = GIT_CONFIG_BACKEND_VERSION;
- git_mutex_init(&backend->header.values_mutex);
-
- backend->snapshot_from = (diskfile_backend *) in;
-
- backend->header.parent.readonly = 1;
- backend->header.parent.version = GIT_CONFIG_BACKEND_VERSION;
- backend->header.parent.open = config_readonly_open;
- backend->header.parent.get = config_get;
- backend->header.parent.set = config_set_readonly;
- backend->header.parent.set_multivar = config_set_multivar_readonly;
- backend->header.parent.del = config_delete_readonly;
- backend->header.parent.del_multivar = config_delete_multivar_readonly;
- backend->header.parent.iterator = config_iterator_new;
- backend->header.parent.lock = config_lock_readonly;
- backend->header.parent.unlock = config_unlock_readonly;
- backend->header.parent.free = backend_readonly_free;
+ backend->parent.open = config_file_open;
+ backend->parent.get = config_file_get;
+ backend->parent.set = config_file_set;
+ backend->parent.set_multivar = config_file_set_multivar;
+ backend->parent.del = config_file_delete;
+ backend->parent.del_multivar = config_file_delete_multivar;
+ backend->parent.iterator = config_file_iterator;
+ backend->parent.snapshot = config_file_snapshot;
+ backend->parent.lock = config_file_lock;
+ backend->parent.unlock = config_file_unlock;
+ backend->parent.free = config_file_free;
*out = (git_config_backend *)backend;
return git_buf_detach(&buf);
}
-static int parse_include(git_config_parser *reader,
- diskfile_parse_state *parse_data, const char *file)
+static int parse_include(config_file_parse_data *parse_data, const char *file)
{
- struct config_file *include;
+ config_file *include;
git_buf path = GIT_BUF_INIT;
char *dir;
int result;
if (!file)
return 0;
- if ((result = git_path_dirname_r(&path, reader->file->path)) < 0)
+ if ((result = git_path_dirname_r(&path, parse_data->file->path)) < 0)
return result;
dir = git_buf_detach(&path);
if (result < 0)
return result;
- include = git_array_alloc(reader->file->includes);
+ include = git_array_alloc(parse_data->file->includes);
GIT_ERROR_CHECK_ALLOC(include);
memset(include, 0, sizeof(*include));
git_array_init(include->includes);
include->path = git_buf_detach(&path);
- result = config_read(parse_data->entries, parse_data->repo,
- include, parse_data->level, parse_data->depth+1);
+ result = config_file_read(parse_data->entries, parse_data->repo, include,
+ parse_data->level, parse_data->depth+1);
if (result == GIT_ENOTFOUND) {
git_error_clear();
int *matches,
const git_repository *repo,
const char *cfg_file,
- const char *value,
+ const char *condition,
bool case_insensitive)
{
- git_buf path = GIT_BUF_INIT;
- int error, fnmatch_flags;
-
- if (value[0] == '.' && git_path_is_dirsep(value[1])) {
- git_path_dirname_r(&path, cfg_file);
- git_buf_joinpath(&path, path.ptr, value + 2);
- } else if (value[0] == '~' && git_path_is_dirsep(value[1]))
- git_sysdir_expand_global_file(&path, value + 1);
- else if (!git_path_is_absolute(value))
- git_buf_joinpath(&path, "**", value);
+ git_buf pattern = GIT_BUF_INIT, gitdir = GIT_BUF_INIT;
+ int error;
+
+ if (condition[0] == '.' && git_path_is_dirsep(condition[1])) {
+ git_path_dirname_r(&pattern, cfg_file);
+ git_buf_joinpath(&pattern, pattern.ptr, condition + 2);
+ } else if (condition[0] == '~' && git_path_is_dirsep(condition[1]))
+ git_sysdir_expand_global_file(&pattern, condition + 1);
+ else if (!git_path_is_absolute(condition))
+ git_buf_joinpath(&pattern, "**", condition);
else
- git_buf_sets(&path, value);
+ git_buf_sets(&pattern, condition);
+
+ if (git_path_is_dirsep(condition[strlen(condition) - 1]))
+ git_buf_puts(&pattern, "**");
- if (git_buf_oom(&path)) {
+ if (git_buf_oom(&pattern)) {
error = -1;
goto out;
}
- if (git_path_is_dirsep(value[strlen(value) - 1]))
- git_buf_puts(&path, "**");
-
- fnmatch_flags = FNM_PATHNAME|FNM_LEADING_DIR;
- if (case_insensitive)
- fnmatch_flags |= FNM_IGNORECASE;
-
- if ((error = p_fnmatch(path.ptr, git_repository_path(repo), fnmatch_flags)) < 0)
+ if ((error = git_repository_item_path(&gitdir, repo, GIT_REPOSITORY_ITEM_GITDIR)) < 0)
goto out;
- *matches = (error == 0);
+ if (git_path_is_dirsep(gitdir.ptr[gitdir.size - 1]))
+ git_buf_truncate(&gitdir, gitdir.size - 1);
+ *matches = wildmatch(pattern.ptr, gitdir.ptr,
+ WM_PATHNAME | (case_insensitive ? WM_CASEFOLD : 0)) == WM_MATCH;
out:
- git_buf_dispose(&path);
+ git_buf_dispose(&pattern);
+ git_buf_dispose(&gitdir);
return error;
}
return do_match_gitdir(matches, repo, cfg_file, value, true);
}
+static int conditional_match_onbranch(
+ int *matches,
+ const git_repository *repo,
+ const char *cfg_file,
+ const char *condition)
+{
+ git_buf reference = GIT_BUF_INIT, buf = GIT_BUF_INIT;
+ int error;
+
+ GIT_UNUSED(cfg_file);
+
+ /*
+ * NOTE: you cannot use `git_repository_head` here. Looking up the
+ * HEAD reference will create the ODB, which causes us to read the
+ * repo's config for keys like core.precomposeUnicode. As we're
+ * just parsing the config right now, though, this would result in
+ * an endless recursion.
+ */
+
+ if ((error = git_buf_joinpath(&buf, git_repository_path(repo), GIT_HEAD_FILE)) < 0 ||
+ (error = git_futils_readbuffer(&reference, buf.ptr)) < 0)
+ goto out;
+ git_buf_rtrim(&reference);
+
+ if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)))
+ goto out;
+ git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
+
+ if (git__strncmp(reference.ptr, GIT_REFS_HEADS_DIR, strlen(GIT_REFS_HEADS_DIR)))
+ goto out;
+ git_buf_consume(&reference, reference.ptr + strlen(GIT_REFS_HEADS_DIR));
+
+ /*
+ * If the condition ends with a '/', then we should treat it as if
+ * it had '**' appended.
+ */
+ if ((error = git_buf_sets(&buf, condition)) < 0)
+ goto out;
+ if (git_path_is_dirsep(condition[strlen(condition) - 1]) &&
+ (error = git_buf_puts(&buf, "**")) < 0)
+ goto out;
+
+ *matches = wildmatch(buf.ptr, reference.ptr, WM_PATHNAME) == WM_MATCH;
+out:
+ git_buf_dispose(&reference);
+ git_buf_dispose(&buf);
+
+ return error;
+
+}
+
static const struct {
const char *prefix;
int (*matches)(int *matches, const git_repository *repo, const char *cfg, const char *value);
} conditions[] = {
{ "gitdir:", conditional_match_gitdir },
- { "gitdir/i:", conditional_match_gitdir_i }
+ { "gitdir/i:", conditional_match_gitdir_i },
+ { "onbranch:", conditional_match_onbranch }
};
-static int parse_conditional_include(git_config_parser *reader,
- diskfile_parse_state *parse_data, const char *section, const char *file)
+static int parse_conditional_include(config_file_parse_data *parse_data, const char *section, const char *file)
{
char *condition;
size_t i;
if ((error = conditions[i].matches(&matches,
parse_data->repo,
- parse_data->file_path,
+ parse_data->file->path,
condition + strlen(conditions[i].prefix))) < 0)
break;
if (matches)
- error = parse_include(reader, parse_data, file);
+ error = parse_include(parse_data, file);
break;
}
size_t line_len,
void *data)
{
- diskfile_parse_state *parse_data = (diskfile_parse_state *)data;
+ config_file_parse_data *parse_data = (config_file_parse_data *)data;
git_buf buf = GIT_BUF_INIT;
git_config_entry *entry;
const char *c;
int result = 0;
+ GIT_UNUSED(reader);
GIT_UNUSED(line);
GIT_UNUSED(line_len);
/* Add or append the new config option */
if (!git__strcmp(entry->name, "include.path"))
- result = parse_include(reader, parse_data, entry->value);
+ result = parse_include(parse_data, entry->value);
else if (!git__prefixcmp(entry->name, "includeif.") &&
!git__suffixcmp(entry->name, ".path"))
- result = parse_conditional_include(reader, parse_data,
- entry->name, entry->value);
+ result = parse_conditional_include(parse_data, entry->name, entry->value);
return result;
}
-static int config_read(
+static int config_file_read_buffer(
git_config_entries *entries,
const git_repository *repo,
- git_config_file *file,
+ config_file *file,
git_config_level_t level,
- int depth)
+ int depth,
+ const char *buf,
+ size_t buflen)
{
- diskfile_parse_state parse_data;
+ config_file_parse_data parse_data;
git_config_parser reader;
- git_buf contents = GIT_BUF_INIT;
int error;
if (depth >= MAX_INCLUDE_DEPTH) {
return -1;
}
- if ((error = git_futils_readbuffer(&contents, file->path)) < 0)
- goto out;
-
- git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
-
- if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0)
- goto out;
-
/* Initialize the reading position */
- reader.file = file;
- git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
+ reader.path = file->path;
+ git_parse_ctx_init(&reader.ctx, buf, buflen);
/* If the file is empty, there's nothing for us to do */
- if (!reader.ctx.content || *reader.ctx.content == '\0')
+ if (!reader.ctx.content || *reader.ctx.content == '\0') {
+ error = 0;
goto out;
+ }
parse_data.repo = repo;
- parse_data.file_path = file->path;
+ parse_data.file = file;
parse_data.entries = entries;
parse_data.level = level;
parse_data.depth = depth;
error = git_config_parse(&reader, NULL, read_on_variable, NULL, NULL, &parse_data);
+out:
+ return error;
+}
+
+static int config_file_read(
+ git_config_entries *entries,
+ const git_repository *repo,
+ config_file *file,
+ git_config_level_t level,
+ int depth)
+{
+ git_buf contents = GIT_BUF_INIT;
+ struct stat st;
+ int error;
+
+ if (p_stat(file->path, &st) < 0) {
+ error = git_path_set_error(errno, file->path, "stat");
+ goto out;
+ }
+
+ if ((error = git_futils_readbuffer(&contents, file->path)) < 0)
+ goto out;
+
+ git_futils_filestamp_set_from_stat(&file->stamp, &st);
+ if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0)
+ goto out;
+
+ if ((error = config_file_read_buffer(entries, repo, file, level, depth,
+ contents.ptr, contents.size)) < 0)
+ goto out;
+
out:
git_buf_dispose(&contents);
return error;
const char *section;
const char *orig_name;
const char *name;
- const regex_t *preg;
+ const git_regexp *preg;
const char *value;
};
/* If we have a regex to match the value, see if it matches */
if (has_matched && write_data->preg != NULL)
- has_matched = (regexec(write_data->preg, var_value, 0, NULL, 0) == 0);
+ has_matched = (git_regexp_match(write_data->preg, var_value) == 0);
/* If this isn't the name/value we're looking for, simply dump the
* existing data back out and continue on.
/*
* This is pretty much the parsing, except we write out anything we don't have
*/
-static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char* value)
+static int config_file_write(config_file_backend *cfg, const char *orig_key, const char *key, const git_regexp *preg, const char* value)
+
{
- int result;
- char *orig_section, *section, *orig_name, *name, *ldot;
- git_filebuf file = GIT_FILEBUF_INIT;
+ char *orig_section = NULL, *section = NULL, *orig_name, *name, *ldot;
git_buf buf = GIT_BUF_INIT, contents = GIT_BUF_INIT;
- git_config_parser reader;
+ git_config_parser parser = GIT_CONFIG_PARSER_INIT;
+ git_filebuf file = GIT_FILEBUF_INIT;
struct write_data write_data;
+ int error;
- memset(&reader, 0, sizeof(reader));
- reader.file = &cfg->file;
+ memset(&write_data, 0, sizeof(write_data));
if (cfg->locked) {
- result = git_buf_puts(&contents, git_buf_cstr(&cfg->locked_content) == NULL ? "" : git_buf_cstr(&cfg->locked_content));
+ error = git_buf_puts(&contents, git_buf_cstr(&cfg->locked_content) == NULL ? "" : git_buf_cstr(&cfg->locked_content));
} else {
- /* Lock the file */
- if ((result = git_filebuf_open(
- &file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) {
- git_buf_dispose(&contents);
- return result;
- }
+ if ((error = git_filebuf_open(&file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS,
+ GIT_CONFIG_FILE_MODE)) < 0)
+ goto done;
/* We need to read in our own config file */
- result = git_futils_readbuffer(&contents, cfg->file.path);
+ error = git_futils_readbuffer(&contents, cfg->file.path);
}
+ if (error < 0 && error != GIT_ENOTFOUND)
+ goto done;
- /* Initialise the reading position */
- if (result == 0 || result == GIT_ENOTFOUND) {
- git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size);
- } else {
- git_filebuf_cleanup(&file);
- return -1; /* OS error when reading the file */
- }
+ if ((git_config_parser_init(&parser, cfg->file.path, contents.ptr, contents.size)) < 0)
+ goto done;
ldot = strrchr(key, '.');
name = ldot + 1;
GIT_ERROR_CHECK_ALLOC(orig_section);
write_data.buf = &buf;
- git_buf_init(&write_data.buffered_comment, 0);
write_data.orig_section = orig_section;
write_data.section = section;
- write_data.in_section = 0;
- write_data.preg_replaced = 0;
write_data.orig_name = orig_name;
write_data.name = name;
write_data.preg = preg;
write_data.value = value;
- result = git_config_parse(&reader,
- write_on_section,
- write_on_variable,
- write_on_comment,
- write_on_eof,
- &write_data);
- git__free(section);
- git__free(orig_section);
- git_buf_dispose(&write_data.buffered_comment);
-
- if (result < 0) {
- git_filebuf_cleanup(&file);
+ if ((error = git_config_parse(&parser, write_on_section, write_on_variable,
+ write_on_comment, write_on_eof, &write_data)) < 0)
goto done;
- }
if (cfg->locked) {
size_t len = buf.asize;
git_buf_attach(&cfg->locked_content, git_buf_detach(&buf), len);
} else {
git_filebuf_write(&file, git_buf_cstr(&buf), git_buf_len(&buf));
- result = git_filebuf_commit(&file);
+
+ if ((error = git_filebuf_commit(&file)) < 0)
+ goto done;
+
+ if ((error = config_file_refresh_from_buffer(&cfg->parent, buf.ptr, buf.size)) < 0)
+ goto done;
}
done:
+ git__free(section);
+ git__free(orig_section);
+ git_buf_dispose(&write_data.buffered_comment);
git_buf_dispose(&buf);
git_buf_dispose(&contents);
- git_parse_ctx_clear(&reader.ctx);
- return result;
+ git_filebuf_cleanup(&file);
+ git_config_parser_dispose(&parser);
+
+ return error;
}
static int config_memory_open(git_config_backend *backend, git_config_level_t level, const git_repository *repo)
{
config_memory_backend *memory_backend = (config_memory_backend *) backend;
+ git_config_parser parser = GIT_PARSE_CTX_INIT;
config_memory_parse_data parse_data;
- git_config_parser reader;
+ int error;
GIT_UNUSED(repo);
- if (memory_backend->cfg.size == 0)
- return 0;
-
- git_parse_ctx_init(&reader.ctx, memory_backend->cfg.ptr, memory_backend->cfg.size);
- reader.file = NULL;
+ if ((error = git_config_parser_init(&parser, "in-memory", memory_backend->cfg.ptr,
+ memory_backend->cfg.size)) < 0)
+ goto out;
parse_data.entries = memory_backend->entries;
parse_data.level = level;
- return git_config_parse(&reader, NULL, read_variable_cb, NULL, NULL, &parse_data);
+ if ((error = git_config_parse(&parser, NULL, read_variable_cb, NULL, NULL, &parse_data)) < 0)
+ goto out;
+
+out:
+ git_config_parser_dispose(&parser);
+ return error;
}
static int config_memory_get(git_config_backend *backend, const char *key, git_config_entry **out)
return config_error_readonly();
}
-static int config_memory_snapshot(git_config_backend **out, git_config_backend *backend)
-{
- GIT_UNUSED(out);
- GIT_UNUSED(backend);
- git_error_set(GIT_ERROR_CONFIG, "this backend does not support snapshots");
- return -1;
-}
-
static void config_memory_free(git_config_backend *_backend)
{
config_memory_backend *backend = (config_memory_backend *)_backend;
backend->parent.iterator = config_memory_iterator;
backend->parent.lock = config_memory_lock;
backend->parent.unlock = config_memory_unlock;
- backend->parent.snapshot = config_memory_snapshot;
+ backend->parent.snapshot = git_config_backend_snapshot;
backend->parent.free = config_memory_free;
*out = (git_config_backend *)backend;
static void set_parse_error(git_config_parser *reader, int col, const char *error_str)
{
- const char *file = reader->file ? reader->file->path : "in-memory";
- git_error_set(GIT_ERROR_CONFIG, "failed to parse config file: %s (in %s:%"PRIuZ", column %d)",
- error_str, file, reader->ctx.line_num, col);
+ if (col)
+ git_error_set(GIT_ERROR_CONFIG,
+ "failed to parse config file: %s (in %s:%"PRIuZ", column %d)",
+ error_str, reader->path, reader->ctx.line_num, col);
+ else
+ git_error_set(GIT_ERROR_CONFIG,
+ "failed to parse config file: %s (in %s:%"PRIuZ")",
+ error_str, reader->path, reader->ctx.line_num);
}
}
-static int parse_section_header_ext(git_config_parser *reader, const char *line, const char *base_name, char **section_name)
+static int parse_subsection_header(git_config_parser *reader, const char *line, size_t pos, const char *base_name, char **section_name)
{
int c, rpos;
- char *first_quote, *last_quote;
+ const char *first_quote, *last_quote;
const char *line_start = line;
git_buf buf = GIT_BUF_INIT;
size_t quoted_len, alloc_len, base_name_len = strlen(base_name);
- /*
- * base_name is what came before the space. We should be at the
- * first quotation mark, except for now, line isn't being kept in
- * sync so we only really use it to calculate the length.
- */
+ /* Skip any additional whitespace before our section name */
+ while (git__isspace(line[pos]))
+ pos++;
- first_quote = strchr(line, '"');
- if (first_quote == NULL) {
- set_parse_error(reader, 0, "Missing quotation marks in section header");
+ /* We should be at the first quotation mark. */
+ if (line[pos] != '"') {
+ set_parse_error(reader, 0, "missing quotation marks in section header");
goto end_error;
}
+ first_quote = &line[pos];
last_quote = strrchr(line, '"');
quoted_len = last_quote - first_quote;
+ if ((last_quote - line) > INT_MAX) {
+ set_parse_error(reader, 0, "invalid section header, line too long");
+ goto end_error;
+ }
+
if (quoted_len == 0) {
- set_parse_error(reader, 0, "Missing closing quotation mark in section header");
+ set_parse_error(reader, 0, "missing closing quotation mark in section header");
goto end_error;
}
switch (c) {
case 0:
- set_parse_error(reader, 0, "Unexpected end-of-line in section header");
+ set_parse_error(reader, 0, "unexpected end-of-line in section header");
goto end_error;
case '"':
c = line[++rpos];
if (c == 0) {
- set_parse_error(reader, rpos, "Unexpected end-of-line in section header");
+ set_parse_error(reader, rpos, "unexpected end-of-line in section header");
goto end_error;
}
goto end_error;
if (line[rpos] != '"' || line[rpos + 1] != ']') {
- set_parse_error(reader, rpos, "Unexpected text after closing quotes");
+ set_parse_error(reader, rpos, "unexpected text after closing quotes");
git_buf_dispose(&buf);
return -1;
}
*section_name = git_buf_detach(&buf);
- return &line[rpos + 2] - line_start; /* rpos is at the closing quote */
+ return (int)(&line[rpos + 2] - line_start); /* rpos is at the closing quote */
end_error:
git_buf_dispose(&buf);
name_end = strrchr(line, ']');
if (name_end == NULL) {
git__free(line);
- set_parse_error(reader, 0, "Missing ']' in section header");
+ set_parse_error(reader, 0, "missing ']' in section header");
return -1;
}
do {
if (git__isspace(c)){
name[name_length] = '\0';
- result = parse_section_header_ext(reader, line, name, section_out);
+ result = parse_subsection_header(reader, line, pos, name, section_out);
git__free(line);
git__free(name);
return result;
}
if (!config_keychar(c) && c != '.') {
- set_parse_error(reader, pos, "Unexpected character in header");
+ set_parse_error(reader, pos, "unexpected character in header");
goto fail_parse;
}
} while ((c = line[pos++]) != ']');
if (line[pos - 1] != ']') {
- set_parse_error(reader, pos, "Unexpected end of file");
+ set_parse_error(reader, pos, "unexpected end of file");
goto fail_parse;
}
name_end++;
if (line == name_end) {
- set_parse_error(reader, 0, "Invalid configuration key");
+ set_parse_error(reader, 0, "invalid configuration key");
return -1;
}
if (*value_start == '=') {
*value = value_start + 1;
} else if (*value_start) {
- set_parse_error(reader, 0, "Invalid configuration key");
+ set_parse_error(reader, 0, "invalid configuration key");
return -1;
}
git_buf_attach(&multi_value, value, 0);
value = NULL;
- if (parse_multiline_variable(reader, &multi_value, quote_count) < 0 ||
+ if (parse_multiline_variable(reader, &multi_value, quote_count % 2) < 0 ||
git_buf_oom(&multi_value)) {
error = -1;
git_buf_dispose(&multi_value);
return error;
}
+int git_config_parser_init(git_config_parser *out, const char *path, const char *data, size_t datalen)
+{
+ out->path = path;
+ return git_parse_ctx_init(&out->ctx, data, datalen);
+}
+
+void git_config_parser_dispose(git_config_parser *parser)
+{
+ git_parse_ctx_clear(&parser->ctx);
+}
+
int git_config_parse(
git_config_parser *parser,
git_config_parser_section_cb on_section,
git_config_parser_variable_cb on_variable,
git_config_parser_comment_cb on_comment,
git_config_parser_eof_cb on_eof,
- void *data)
+ void *payload)
{
git_parse_ctx *ctx;
char *current_section = NULL, *var_name = NULL, *var_value = NULL;
git_parse_advance_chars(ctx, result);
if (on_section)
- result = on_section(parser, current_section, line_start, line_len, data);
+ result = on_section(parser, current_section, line_start, line_len, payload);
/*
* After we've parsed the section header we may not be
* done with the line. If there's still data in there,
case ';':
case '#':
if (on_comment) {
- result = on_comment(parser, line_start, line_len, data);
+ result = on_comment(parser, line_start, line_len, payload);
}
break;
default: /* assume variable declaration */
if ((result = parse_variable(parser, &var_name, &var_value)) == 0 && on_variable) {
- result = on_variable(parser, current_section, var_name, var_value, line_start, line_len, data);
+ result = on_variable(parser, current_section, var_name, var_value, line_start, line_len, payload);
git__free(var_name);
git__free(var_value);
}
}
if (on_eof)
- result = on_eof(parser, current_section, data);
+ result = on_eof(parser, current_section, payload);
out:
git__free(current_section);
#define INCLUDE_config_parse_h__
#include "common.h"
+
#include "array.h"
+#include "futils.h"
#include "oid.h"
#include "parse.h"
extern const char *git_config_escapes;
extern const char *git_config_escaped;
-typedef struct config_file {
- git_oid checksum;
- char *path;
- git_array_t(struct config_file) includes;
-} git_config_file;
-
typedef struct {
- struct config_file *file;
+ const char *path;
git_parse_ctx ctx;
} git_config_parser;
+#define GIT_CONFIG_PARSER_INIT { NULL, GIT_PARSE_CTX_INIT }
+
typedef int (*git_config_parser_section_cb)(
git_config_parser *parser,
const char *current_section,
const char *line,
size_t line_len,
- void *data);
+ void *payload);
typedef int (*git_config_parser_variable_cb)(
git_config_parser *parser,
const char *var_value,
const char *line,
size_t line_len,
- void *data);
+ void *payload);
typedef int (*git_config_parser_comment_cb)(
git_config_parser *parser,
const char *line,
size_t line_len,
- void *data);
+ void *payload);
typedef int (*git_config_parser_eof_cb)(
git_config_parser *parser,
const char *current_section,
- void *data);
+ void *payload);
+
+int git_config_parser_init(git_config_parser *out, const char *path, const char *data, size_t datalen);
+void git_config_parser_dispose(git_config_parser *parser);
int git_config_parse(
git_config_parser *parser,
git_config_parser_variable_cb on_variable,
git_config_parser_comment_cb on_comment,
git_config_parser_eof_cb on_eof,
- void *data);
+ void *payload);
#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "config_backend.h"
+
+#include "config.h"
+#include "config_entries.h"
+
+typedef struct {
+ git_config_backend parent;
+ git_mutex values_mutex;
+ git_config_entries *entries;
+ git_config_backend *source;
+} config_snapshot_backend;
+
+static int config_error_readonly(void)
+{
+ git_error_set(GIT_ERROR_CONFIG, "this backend is read-only");
+ return -1;
+}
+
+static int config_snapshot_iterator(
+ git_config_iterator **iter,
+ struct git_config_backend *backend)
+{
+ config_snapshot_backend *b = GIT_CONTAINER_OF(backend, config_snapshot_backend, parent);
+ git_config_entries *entries = NULL;
+ int error;
+
+ if ((error = git_config_entries_dup(&entries, b->entries)) < 0 ||
+ (error = git_config_entries_iterator_new(iter, entries)) < 0)
+ goto out;
+
+out:
+ /* Let iterator delete duplicated entries when it's done */
+ git_config_entries_free(entries);
+ return error;
+}
+
+/* release the map containing the entry as an equivalent to freeing it */
+static void config_snapshot_entry_free(git_config_entry *entry)
+{
+ git_config_entries *entries = (git_config_entries *) entry->payload;
+ git_config_entries_free(entries);
+}
+
+static int config_snapshot_get(git_config_backend *cfg, const char *key, git_config_entry **out)
+{
+ config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent);
+ git_config_entries *entries = NULL;
+ git_config_entry *entry;
+ int error = 0;
+
+ if (git_mutex_lock(&b->values_mutex) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to lock config backend");
+ return -1;
+ }
+
+ entries = b->entries;
+ git_config_entries_incref(entries);
+ git_mutex_unlock(&b->values_mutex);
+
+ if ((error = (git_config_entries_get(&entry, entries, key))) < 0) {
+ git_config_entries_free(entries);
+ return error;
+ }
+
+ entry->free = config_snapshot_entry_free;
+ entry->payload = entries;
+ *out = entry;
+
+ return 0;
+}
+
+static int config_snapshot_set(git_config_backend *cfg, const char *name, const char *value)
+{
+ GIT_UNUSED(cfg);
+ GIT_UNUSED(name);
+ GIT_UNUSED(value);
+
+ return config_error_readonly();
+}
+
+static int config_snapshot_set_multivar(
+ git_config_backend *cfg, const char *name, const char *regexp, const char *value)
+{
+ GIT_UNUSED(cfg);
+ GIT_UNUSED(name);
+ GIT_UNUSED(regexp);
+ GIT_UNUSED(value);
+
+ return config_error_readonly();
+}
+
+static int config_snapshot_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp)
+{
+ GIT_UNUSED(cfg);
+ GIT_UNUSED(name);
+ GIT_UNUSED(regexp);
+
+ return config_error_readonly();
+}
+
+static int config_snapshot_delete(git_config_backend *cfg, const char *name)
+{
+ GIT_UNUSED(cfg);
+ GIT_UNUSED(name);
+
+ return config_error_readonly();
+}
+
+static int config_snapshot_lock(git_config_backend *_cfg)
+{
+ GIT_UNUSED(_cfg);
+
+ return config_error_readonly();
+}
+
+static int config_snapshot_unlock(git_config_backend *_cfg, int success)
+{
+ GIT_UNUSED(_cfg);
+ GIT_UNUSED(success);
+
+ return config_error_readonly();
+}
+
+static void config_snapshot_free(git_config_backend *_backend)
+{
+ config_snapshot_backend *backend = GIT_CONTAINER_OF(_backend, config_snapshot_backend, parent);
+
+ if (backend == NULL)
+ return;
+
+ git_config_entries_free(backend->entries);
+ git_mutex_free(&backend->values_mutex);
+ git__free(backend);
+}
+
+static int config_snapshot_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo)
+{
+ config_snapshot_backend *b = GIT_CONTAINER_OF(cfg, config_snapshot_backend, parent);
+ git_config_entries *entries = NULL;
+ git_config_iterator *it = NULL;
+ git_config_entry *entry;
+ int error;
+
+ /* We're just copying data, don't care about the level or repo*/
+ GIT_UNUSED(level);
+ GIT_UNUSED(repo);
+
+ if ((error = git_config_entries_new(&entries)) < 0 ||
+ (error = b->source->iterator(&it, b->source)) < 0)
+ goto out;
+
+ while ((error = git_config_next(&entry, it)) == 0)
+ if ((error = git_config_entries_dup_entry(entries, entry)) < 0)
+ goto out;
+
+ if (error < 0) {
+ if (error != GIT_ITEROVER)
+ goto out;
+ error = 0;
+ }
+
+ b->entries = entries;
+
+out:
+ git_config_iterator_free(it);
+ if (error)
+ git_config_entries_free(entries);
+ return error;
+}
+
+int git_config_backend_snapshot(git_config_backend **out, git_config_backend *source)
+{
+ config_snapshot_backend *backend;
+
+ backend = git__calloc(1, sizeof(config_snapshot_backend));
+ GIT_ERROR_CHECK_ALLOC(backend);
+
+ backend->parent.version = GIT_CONFIG_BACKEND_VERSION;
+ git_mutex_init(&backend->values_mutex);
+
+ backend->source = source;
+
+ backend->parent.readonly = 1;
+ backend->parent.version = GIT_CONFIG_BACKEND_VERSION;
+ backend->parent.open = config_snapshot_open;
+ backend->parent.get = config_snapshot_get;
+ backend->parent.set = config_snapshot_set;
+ backend->parent.set_multivar = config_snapshot_set_multivar;
+ backend->parent.snapshot = git_config_backend_snapshot;
+ backend->parent.del = config_snapshot_delete;
+ backend->parent.del_multivar = config_snapshot_delete_multivar;
+ backend->parent.iterator = config_snapshot_iterator;
+ backend->parent.lock = config_snapshot_lock;
+ backend->parent.unlock = config_snapshot_unlock;
+ backend->parent.free = config_snapshot_free;
+
+ *out = &backend->parent;
+
+ return 0;
+}
#include "git2/index.h"
#include "git2/sys/filter.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "filter.h"
#include "buf_text.h"
static git_crlf_t check_crlf(const char *value)
{
- if (GIT_ATTR_TRUE(value))
+ if (GIT_ATTR_IS_TRUE(value))
return GIT_CRLF_TEXT;
- else if (GIT_ATTR_FALSE(value))
+ else if (GIT_ATTR_IS_FALSE(value))
return GIT_CRLF_BINARY;
- else if (GIT_ATTR_UNSPECIFIED(value))
+ else if (GIT_ATTR_IS_UNSPECIFIED(value))
;
else if (strcmp(value, "input") == 0)
return GIT_CRLF_TEXT_INPUT;
return GIT_CRLF_UNDEFINED;
}
-static git_cvar_value check_eol(const char *value)
+static git_configmap_value check_eol(const char *value)
{
- if (GIT_ATTR_UNSPECIFIED(value))
+ if (GIT_ATTR_IS_UNSPECIFIED(value))
;
else if (strcmp(value, "lf") == 0)
return GIT_EOL_LF;
const git_index_entry *entry;
git_blob *blob;
const void *blobcontent;
- git_off_t blobsize;
+ git_object_size_t blobsize;
bool found_cr;
if (!path)
return 0;
}
-static git_cvar_value output_eol(struct crlf_attrs *ca)
+static git_configmap_value output_eol(struct crlf_attrs *ca)
{
switch (ca->crlf_action) {
case GIT_CRLF_BINARY:
memset(ca, 0, sizeof(struct crlf_attrs));
- if ((error = git_repository__cvar(&ca->auto_crlf,
- git_filter_source_repo(src), GIT_CVAR_AUTO_CRLF)) < 0 ||
- (error = git_repository__cvar(&ca->safe_crlf,
- git_filter_source_repo(src), GIT_CVAR_SAFE_CRLF)) < 0 ||
- (error = git_repository__cvar(&ca->core_eol,
- git_filter_source_repo(src), GIT_CVAR_EOL)) < 0)
+ if ((error = git_repository__configmap_lookup(&ca->auto_crlf,
+ git_filter_source_repo(src), GIT_CONFIGMAP_AUTO_CRLF)) < 0 ||
+ (error = git_repository__configmap_lookup(&ca->safe_crlf,
+ git_filter_source_repo(src), GIT_CONFIGMAP_SAFE_CRLF)) < 0 ||
+ (error = git_repository__configmap_lookup(&ca->core_eol,
+ git_filter_source_repo(src), GIT_CONFIGMAP_EOL)) < 0)
return error;
/* downgrade FAIL to WARN if ALLOW_UNSAFE option is used */
#include "commit_list.h"
#include "oidmap.h"
#include "refs.h"
+#include "repository.h"
#include "revwalk.h"
#include "tag.h"
#include "vector.h"
-#include "repository.h"
+#include "wildmatch.h"
/* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */
static void *oidmap_value_bykey(git_oidmap *map, const git_oid *key)
{
- size_t pos = git_oidmap_lookup_index(map, key);
-
- if (!git_oidmap_valid_index(map, pos))
- return NULL;
-
- return git_oidmap_value_at(map, pos);
+ return git_oidmap_get(map, key);
}
static struct commit_name *find_commit_name(
e->path = git__strdup(path);
git_oid_cpy(&e->peeled, peeled);
- if (!found) {
- int ret;
-
- git_oidmap_insert(names, &e->peeled, e, &ret);
- if (ret < 0)
- return -1;
- }
+ if (!found && git_oidmap_set(names, &e->peeled, e) < 0)
+ return -1;
}
else
git_tag_free(tag);
return 0;
/* Accept only tags that match the pattern, if given */
- if (data->opts->pattern && (!is_tag || p_fnmatch(data->opts->pattern,
+ if (data->opts->pattern && (!is_tag || wildmatch(data->opts->pattern,
refname + strlen(GIT_REFS_TAGS_DIR), 0)))
return 0;
"git_describe_options");
data.opts = &normalized;
- data.names = git_oidmap_alloc();
- GIT_ERROR_CHECK_ALLOC(data.names);
+ if ((error = git_oidmap_new(&data.names)) < 0)
+ return error;
/** TODO: contains to be implemented */
get_name, &data)) < 0)
goto cleanup;
- if (git_oidmap_size(data.names) == 0 && !opts->show_commit_oid_as_fallback) {
+ if (git_oidmap_size(data.names) == 0 && !normalized.show_commit_oid_as_fallback) {
git_error_set(GIT_ERROR_DESCRIBE, "cannot describe - "
"no reference found, cannot describe anything.");
error = -1;
const git_describe_format_options *src)
{
if (!src) {
- git_describe_init_format_options(dst, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
+ git_describe_format_options_init(dst, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
return 0;
}
git__free(result);
}
-int git_describe_init_options(git_describe_options *opts, unsigned int version)
+int git_describe_options_init(git_describe_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_describe_options, GIT_DESCRIBE_OPTIONS_INIT);
return 0;
}
-int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version)
+#ifndef GIT_DEPRECATE_HARD
+int git_describe_init_options(git_describe_options *opts, unsigned int version)
+{
+ return git_describe_options_init(opts, version);
+}
+#endif
+
+int git_describe_format_options_init(git_describe_format_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_describe_format_options, GIT_DESCRIBE_FORMAT_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version)
+{
+ return git_describe_format_options_init(opts, version);
+}
+#endif
return str;
}
-const char *git_diff_delta__path(const git_diff_delta *delta)
-{
- return diff_delta__path(delta);
-}
-
int git_diff_delta__cmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
return error;
}
-int git_diff_format_email__append_header_tobuf(
+static int diff_format_email_append_header_tobuf(
git_buf *out,
const git_oid *id,
const git_signature *author,
return error;
}
-int git_diff_format_email__append_patches_tobuf(
+static int diff_format_email_append_patches_tobuf(
git_buf *out,
git_diff *diff)
{
strncpy(summary, opts->summary, offset);
}
- error = git_diff_format_email__append_header_tobuf(out,
+ error = diff_format_email_append_header_tobuf(out,
opts->id, opts->author, summary == NULL ? opts->summary : summary,
opts->body, opts->patch_no, opts->total_patches, ignore_marker);
(error = git_diff_get_stats(&stats, diff)) < 0 ||
(error = git_diff_stats_to_buf(out, stats, format_flags, 0)) < 0 ||
(error = git_buf_putc(out, '\n')) < 0 ||
- (error = git_diff_format_email__append_patches_tobuf(out, diff)) < 0)
+ (error = diff_format_email_append_patches_tobuf(out, diff)) < 0)
goto on_error;
error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n");
git_commit *commit,
size_t patch_no,
size_t total_patches,
- git_diff_format_email_flags_t flags,
+ uint32_t flags,
const git_diff_options *diff_opts)
{
git_diff *diff = NULL;
return error;
}
-int git_diff_init_options(git_diff_options *opts, unsigned int version)
+int git_diff_options_init(git_diff_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_diff_options, GIT_DIFF_OPTIONS_INIT);
return 0;
}
-int git_diff_find_init_options(
+#ifndef GIT_DEPRECATE_HARD
+int git_diff_init_options(git_diff_options *opts, unsigned int version)
+{
+ return git_diff_options_init(opts, version);
+}
+#endif
+
+int git_diff_find_options_init(
git_diff_find_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
return 0;
}
-int git_diff_format_email_init_options(
+#ifndef GIT_DEPRECATE_HARD
+int git_diff_find_init_options(
+ git_diff_find_options *opts, unsigned int version)
+{
+ return git_diff_find_options_init(opts, version);
+}
+#endif
+
+int git_diff_format_email_options_init(
git_diff_format_email_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_diff_format_email_init_options(
+ git_diff_format_email_options *opts, unsigned int version)
+{
+ return git_diff_format_email_options_init(opts, version);
+}
+#endif
+
static int flush_hunk(git_oid *result, git_hash_ctx *ctx)
{
git_oid hash;
git_buf_truncate(buf, len);
}
-static int file_cb(
+static int diff_patchid_print_callback_to_buf(
const git_diff_delta *delta,
- float progress,
+ const git_diff_hunk *hunk,
+ const git_diff_line *line,
void *payload)
{
struct patch_id_args *args = (struct patch_id_args *) payload;
git_buf buf = GIT_BUF_INIT;
- int error;
-
- GIT_UNUSED(progress);
+ int error = 0;
- if (!args->first_file &&
- (error = flush_hunk(&args->result, &args->ctx)) < 0)
- goto out;
- args->first_file = 0;
-
- if ((error = git_buf_printf(&buf,
- "diff--gita/%sb/%s---a/%s+++b/%s",
- delta->old_file.path,
- delta->new_file.path,
- delta->old_file.path,
- delta->new_file.path)) < 0)
+ if (line->origin == GIT_DIFF_LINE_CONTEXT_EOFNL ||
+ line->origin == GIT_DIFF_LINE_ADD_EOFNL ||
+ line->origin == GIT_DIFF_LINE_DEL_EOFNL)
goto out;
- strip_spaces(&buf);
-
- if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
+ if ((error = git_diff_print_callback__to_buf(delta, hunk,
+ line, &buf)) < 0)
goto out;
-out:
- git_buf_dispose(&buf);
- return error;
-}
-
-static int line_cb(
- const git_diff_delta *delta,
- const git_diff_hunk *hunk,
- const git_diff_line *line,
- void *payload)
-{
- struct patch_id_args *args = (struct patch_id_args *) payload;
- git_buf buf = GIT_BUF_INIT;
- int error;
-
- GIT_UNUSED(delta);
- GIT_UNUSED(hunk);
-
- switch (line->origin) {
- case GIT_DIFF_LINE_ADDITION:
- git_buf_putc(&buf, '+');
- break;
- case GIT_DIFF_LINE_DELETION:
- git_buf_putc(&buf, '-');
- break;
- case GIT_DIFF_LINE_CONTEXT:
- break;
- default:
- git_error_set(GIT_ERROR_PATCH, "invalid line origin for patch");
- return -1;
- }
-
- git_buf_put(&buf, line->content, line->content_len);
strip_spaces(&buf);
+ if (line->origin == GIT_DIFF_LINE_FILE_HDR &&
+ !args->first_file &&
+ (error = flush_hunk(&args->result, &args->ctx) < 0))
+ goto out;
+
if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
goto out;
+ if (line->origin == GIT_DIFF_LINE_FILE_HDR && args->first_file)
+ args->first_file = 0;
+
out:
git_buf_dispose(&buf);
return error;
}
-int git_diff_patchid_init_options(git_diff_patchid_options *opts, unsigned int version)
+int git_diff_patchid_options_init(git_diff_patchid_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_INIT);
if ((error = git_hash_ctx_init(&args.ctx)) < 0)
goto out;
- if ((error = git_diff_foreach(diff, file_cb, NULL, NULL, line_cb, &args)) < 0)
+ if ((error = git_diff_print(diff,
+ GIT_DIFF_FORMAT_PATCH_ID,
+ diff_patchid_print_callback_to_buf,
+ &args)) < 0)
goto out;
if ((error = (flush_hunk(&args.result, &args.ctx))) < 0)
git_diff_options opts;
git_vector deltas; /* vector of git_diff_delta */
git_pool pool;
- git_iterator_type_t old_src;
- git_iterator_type_t new_src;
+ git_iterator_t old_src;
+ git_iterator_t new_src;
git_diff_perfdata perf;
int (*strcomp)(const char *, const char *);
const git_diff_delta *delta,
const char *oldpfx,
const char *newpfx,
- int oid_strlen);
+ int oid_strlen,
+ bool print_index);
extern int git_diff_delta__cmp(const void *a, const void *b);
extern int git_diff_delta__casecmp(const void *a, const void *b);
#include "git2/attr.h"
+#include "common.h"
#include "diff.h"
#include "strmap.h"
#include "map.h"
#include "buf_text.h"
#include "config.h"
+#include "regexp.h"
#include "repository.h"
typedef enum {
} git_diff_driver_t;
typedef struct {
- regex_t re;
+ git_regexp re;
int flags;
} git_diff_driver_pattern;
uint32_t binary_flags;
uint32_t other_flags;
git_array_t(git_diff_driver_pattern) fn_patterns;
- regex_t word_pattern;
+ git_regexp word_pattern;
char name[GIT_FLEX_ARRAY];
};
if (!reg)
return NULL;
- if (git_strmap_alloc(®->drivers) < 0) {
+ if (git_strmap_new(®->drivers) < 0) {
git_diff_driver_registry_free(reg);
return NULL;
}
if (error < 0)
break;
- if ((error = p_regcomp(&pat->re, buf.ptr, regex_flags)) != 0) {
+ if ((error = git_regexp_compile(&pat->re, buf.ptr, regex_flags)) != 0) {
/*
* TODO: issue a warning
*/
static int diff_driver_xfuncname(const git_config_entry *entry, void *payload)
{
- return diff_driver_add_patterns(payload, entry->value, REG_EXTENDED);
+ return diff_driver_add_patterns(payload, entry->value, 0);
}
static int diff_driver_funcname(const git_config_entry *entry, void *payload)
git_diff_driver_registry *reg,
const char *driver_name)
{
- int error = 0;
git_diff_driver_definition *ddef = NULL;
git_diff_driver *drv = NULL;
+ int error = 0;
size_t idx;
for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) {
if (ddef->fns &&
(error = diff_driver_add_patterns(
- drv, ddef->fns, ddef->flags | REG_EXTENDED)) < 0)
+ drv, ddef->fns, ddef->flags)) < 0)
goto done;
if (ddef->words &&
- (error = p_regcomp(
- &drv->word_pattern, ddef->words, ddef->flags | REG_EXTENDED)))
- {
- error = git_error_set_regex(&drv->word_pattern, error);
+ (error = git_regexp_compile(&drv->word_pattern, ddef->words, ddef->flags)) < 0)
goto done;
- }
- git_strmap_insert(reg->drivers, drv->name, drv, &error);
- if (error > 0)
- error = 0;
+ if ((error = git_strmap_set(reg->drivers, drv->name, drv)) < 0)
+ goto done;
done:
if (error && drv)
{
int error = 0;
git_diff_driver_registry *reg;
- git_diff_driver *drv = NULL;
- size_t namelen, pos;
+ git_diff_driver *drv;
+ size_t namelen;
git_config *cfg = NULL;
git_buf name = GIT_BUF_INIT;
git_config_entry *ce = NULL;
if ((reg = git_repository_driver_registry(repo)) == NULL)
return -1;
- pos = git_strmap_lookup_index(reg->drivers, driver_name);
- if (git_strmap_valid_index(reg->drivers, pos)) {
- *out = git_strmap_value_at(reg->drivers, pos);
+ if ((drv = git_strmap_get(reg->drivers, driver_name)) != NULL) {
+ *out = drv;
return 0;
}
/* TODO: warn if diff.<name>.command or diff.<name>.textconv are set */
git_buf_truncate(&name, namelen + strlen("diff.."));
- git_buf_put(&name, "xfuncname", strlen("xfuncname"));
+ if ((error = git_buf_PUTS(&name, "xfuncname")) < 0)
+ goto done;
+
if ((error = git_config_get_multivar_foreach(
cfg, name.ptr, NULL, diff_driver_xfuncname, drv)) < 0) {
if (error != GIT_ENOTFOUND)
}
git_buf_truncate(&name, namelen + strlen("diff.."));
- git_buf_put(&name, "funcname", strlen("funcname"));
+ if ((error = git_buf_PUTS(&name, "funcname")) < 0)
+ goto done;
+
if ((error = git_config_get_multivar_foreach(
cfg, name.ptr, NULL, diff_driver_funcname, drv)) < 0) {
if (error != GIT_ENOTFOUND)
}
git_buf_truncate(&name, namelen + strlen("diff.."));
- git_buf_put(&name, "wordregex", strlen("wordregex"));
+ if ((error = git_buf_PUTS(&name, "wordregex")) < 0)
+ goto done;
+
if ((error = git_config__lookup_entry(&ce, cfg, name.ptr, false)) < 0)
goto done;
if (!ce || !ce->value)
/* no diff.<driver>.wordregex, so just continue */;
- else if (!(error = p_regcomp(&drv->word_pattern, ce->value, REG_EXTENDED)))
+ else if (!(error = git_regexp_compile(&drv->word_pattern, ce->value, 0)))
found_driver = true;
else {
/* TODO: warn about bad regex instead of failure */
- error = git_error_set_regex(&drv->word_pattern, error);
goto done;
}
goto done;
/* store driver in registry */
- git_strmap_insert(reg->drivers, drv->name, drv, &error);
- if (error < 0)
+ if ((error = git_strmap_set(reg->drivers, drv->name, drv)) < 0)
goto done;
- error = 0;
*out = drv;
attrsession, 0, path, 1, attrs)) < 0)
/* return error below */;
- else if (GIT_ATTR_UNSPECIFIED(values[0]))
+ else if (GIT_ATTR_IS_UNSPECIFIED(values[0]))
/* just use the auto value */;
- else if (GIT_ATTR_FALSE(values[0]))
+ else if (GIT_ATTR_IS_FALSE(values[0]))
*out = &global_drivers[DIFF_DRIVER_BINARY];
- else if (GIT_ATTR_TRUE(values[0]))
+ else if (GIT_ATTR_IS_TRUE(values[0]))
*out = &global_drivers[DIFF_DRIVER_TEXT];
/* otherwise look for driver information in config and build driver */
return;
for (i = 0; i < git_array_size(driver->fn_patterns); ++i)
- regfree(& git_array_get(driver->fn_patterns, i)->re);
+ git_regexp_dispose(& git_array_get(driver->fn_patterns, i)->re);
git_array_clear(driver->fn_patterns);
- regfree(&driver->word_pattern);
+ git_regexp_dispose(&driver->word_pattern);
git__free(driver);
}
git_diff_driver *driver, git_buf *line)
{
size_t i, maxi = git_array_size(driver->fn_patterns);
- regmatch_t pmatch[2];
+ git_regmatch pmatch[2];
for (i = 0; i < maxi; ++i) {
git_diff_driver_pattern *pat = git_array_get(driver->fn_patterns, i);
- if (!regexec(&pat->re, line->ptr, 2, pmatch, 0)) {
+ if (!git_regexp_search(&pat->re, line->ptr, 2, pmatch)) {
if (pat->flags & REG_NEGATE)
return false;
/* use pmatch data to trim line data */
- i = (pmatch[1].rm_so >= 0) ? 1 : 0;
- git_buf_consume(line, git_buf_cstr(line) + pmatch[i].rm_so);
- git_buf_truncate(line, pmatch[i].rm_eo - pmatch[i].rm_so);
+ i = (pmatch[1].start >= 0) ? 1 : 0;
+ git_buf_consume(line, git_buf_cstr(line) + pmatch[i].start);
+ git_buf_truncate(line, pmatch[i].end - pmatch[i].start);
git_buf_rtrim(line);
return true;
#include "diff.h"
#include "diff_generate.h"
#include "odb.h"
-#include "fileops.h"
+#include "futils.h"
#include "filter.h"
#define DIFF_MAX_FILESIZE 0x20000000
fc->opts_max_size = opts->max_size ?
opts->max_size : DIFF_MAX_FILESIZE;
- if (fc->src == GIT_ITERATOR_TYPE_EMPTY)
- fc->src = GIT_ITERATOR_TYPE_TREE;
+ if (fc->src == GIT_ITERATOR_EMPTY)
+ fc->src = GIT_ITERATOR_TREE;
if (!fc->driver &&
git_diff_driver_lookup(&fc->driver, fc->repo,
git_diff_driver_update_options(&fc->opts_flags, fc->driver);
/* make sure file is conceivable mmap-able */
- if ((git_off_t)((size_t)fc->file->size) != fc->file->size)
+ if ((size_t)fc->file->size != fc->file->size)
fc->file->flags |= GIT_DIFF_FLAG_BINARY;
/* check if user is forcing text diff the file */
else if (fc->opts_flags & GIT_DIFF_FORCE_TEXT) {
fc->flags |= GIT_DIFF_FLAG__FREE_BLOB;
} else {
+ int error;
+ if ((error = git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB)) < 0)
+ return error;
fc->file->size = src->buflen;
- git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB);
fc->file->id_abbrev = GIT_OID_HEXSZ;
fc->map.len = src->buflen;
int error = 0;
git_odb_object *odb_obj = NULL;
- if (git_oid_iszero(&fc->file->id))
+ if (git_oid_is_zero(&fc->file->id))
return 0;
if (fc->file->mode == GIT_FILEMODE_COMMIT)
ssize_t alloc_len, read_len;
int symlink_supported, error;
- if ((error = git_repository__cvar(
- &symlink_supported, fc->repo, GIT_CVAR_SYMLINKS)) < 0)
+ if ((error = git_repository__configmap_lookup(
+ &symlink_supported, fc->repo, GIT_CONFIGMAP_SYMLINKS)) < 0)
return -1;
if (!symlink_supported)
if (fd < 0)
return fd;
- if (!fc->file->size &&
- !(fc->file->size = git_futils_filesize(fd)))
+ if (!fc->file->size)
+ error = git_futils_filesize(&fc->file->size, fd);
+
+ if (error < 0 || !fc->file->size)
goto cleanup;
if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
(diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0)
return 0;
- if (fc->src == GIT_ITERATOR_TYPE_WORKDIR)
+ if (fc->src == GIT_ITERATOR_WORKDIR)
error = diff_file_content_load_workdir(fc, diff_opts);
else
error = diff_file_content_load_blob(fc, diff_opts);
git_diff_driver *driver;
uint32_t flags;
uint32_t opts_flags;
- git_off_t opts_max_size;
- git_iterator_type_t src;
+ git_object_size_t opts_max_size;
+ git_iterator_t src;
const git_blob *blob;
git_map map;
} git_diff_file_content;
#include "diff.h"
#include "patch_generate.h"
-#include "fileops.h"
+#include "futils.h"
#include "config.h"
#include "attr_file.h"
#include "filter.h"
delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
- if (has_old || !git_oid_iszero(&delta->new_file.id))
+ if (has_old || !git_oid_is_zero(&delta->new_file.id))
delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
return diff_insert_delta(diff, delta, matched_pathspec);
delta->old_file.flags |= GIT_DIFF_FLAG_EXISTS;
delta->new_file.flags |= GIT_DIFF_FLAG_EXISTS;
- if (!git_oid_iszero(&new_entry->id))
+ if (!git_oid_is_zero(&new_entry->id))
delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
}
delta->old_file.path : delta->new_file.path;
}
-int git_diff_delta__i2w_cmp(const void *a, const void *b)
+static int diff_delta_i2w_cmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
int val = strcmp(diff_delta__i2w_path(da), diff_delta__i2w_path(db));
return val ? val : ((int)da->status - (int)db->status);
}
-int git_diff_delta__i2w_casecmp(const void *a, const void *b)
+static int diff_delta_i2w_casecmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
int val = strcasecmp(diff_delta__i2w_path(da), diff_delta__i2w_path(db));
static const char *diff_mnemonic_prefix(
- git_iterator_type_t type, bool left_side)
+ git_iterator_t type, bool left_side)
{
const char *pfx = "";
switch (type) {
- case GIT_ITERATOR_TYPE_EMPTY: pfx = "c"; break;
- case GIT_ITERATOR_TYPE_TREE: pfx = "c"; break;
- case GIT_ITERATOR_TYPE_INDEX: pfx = "i"; break;
- case GIT_ITERATOR_TYPE_WORKDIR: pfx = "w"; break;
- case GIT_ITERATOR_TYPE_FS: pfx = left_side ? "1" : "2"; break;
+ case GIT_ITERATOR_EMPTY: pfx = "c"; break;
+ case GIT_ITERATOR_TREE: pfx = "c"; break;
+ case GIT_ITERATOR_INDEX: pfx = "i"; break;
+ case GIT_ITERATOR_WORKDIR: pfx = "w"; break;
+ case GIT_ITERATOR_FS: pfx = left_side ? "1" : "2"; break;
default: break;
}
return pfx;
}
-void git_diff__set_ignore_case(git_diff *diff, bool ignore_case)
+static void diff_set_ignore_case(git_diff *diff, bool ignore_case)
{
if (!ignore_case) {
diff->opts.flags &= ~GIT_DIFF_IGNORE_CASE;
git_attr_session__init(&diff->base.attrsession, repo);
memcpy(&diff->base.opts, &dflt, sizeof(git_diff_options));
- git_pool_init(&diff->base.pool, 1);
-
- if (git_vector_init(&diff->base.deltas, 0, git_diff_delta__cmp) < 0) {
+ if (git_pool_init(&diff->base.pool, 1) < 0 ||
+ git_vector_init(&diff->base.deltas, 0, git_diff_delta__cmp) < 0) {
git_diff_free(&diff->base);
return NULL;
}
/* Use case-insensitive compare if either iterator has
* the ignore_case bit set */
- git_diff__set_ignore_case(
+ diff_set_ignore_case(
&diff->base,
git_iterator_ignore_case(old_iter) ||
git_iterator_ignore_case(new_iter));
if ((val = git_repository_config_snapshot(&cfg, repo)) < 0)
return val;
- if (!git_config__cvar(&val, cfg, GIT_CVAR_SYMLINKS) && val)
+ if (!git_config__configmap_lookup(&val, cfg, GIT_CONFIGMAP_SYMLINKS) && val)
diff->diffcaps |= GIT_DIFFCAPS_HAS_SYMLINKS;
- if (!git_config__cvar(&val, cfg, GIT_CVAR_IGNORESTAT) && val)
+ if (!git_config__configmap_lookup(&val, cfg, GIT_CONFIGMAP_IGNORESTAT) && val)
diff->diffcaps |= GIT_DIFFCAPS_IGNORE_STAT;
if ((diff->base.opts.flags & GIT_DIFF_IGNORE_FILEMODE) == 0 &&
- !git_config__cvar(&val, cfg, GIT_CVAR_FILEMODE) && val)
+ !git_config__configmap_lookup(&val, cfg, GIT_CONFIGMAP_FILEMODE) && val)
diff->diffcaps |= GIT_DIFFCAPS_TRUST_MODE_BITS;
- if (!git_config__cvar(&val, cfg, GIT_CVAR_TRUSTCTIME) && val)
+ if (!git_config__configmap_lookup(&val, cfg, GIT_CONFIGMAP_TRUSTCTIME) && val)
diff->diffcaps |= GIT_DIFFCAPS_TRUST_CTIME;
/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
/* Reverse src info if diff is reversed */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
- git_iterator_type_t tmp_src = diff->base.old_src;
+ git_iterator_t tmp_src = diff->base.old_src;
diff->base.old_src = diff->base.new_src;
diff->base.new_src = tmp_src;
}
/* Unset UPDATE_INDEX unless diffing workdir and index */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_UPDATE_INDEX) &&
- (!(diff->base.old_src == GIT_ITERATOR_TYPE_WORKDIR ||
- diff->base.new_src == GIT_ITERATOR_TYPE_WORKDIR) ||
- !(diff->base.old_src == GIT_ITERATOR_TYPE_INDEX ||
- diff->base.new_src == GIT_ITERATOR_TYPE_INDEX)))
+ (!(diff->base.old_src == GIT_ITERATOR_WORKDIR ||
+ diff->base.new_src == GIT_ITERATOR_WORKDIR) ||
+ !(diff->base.old_src == GIT_ITERATOR_INDEX ||
+ diff->base.new_src == GIT_ITERATOR_INDEX)))
diff->base.opts.flags &= ~GIT_DIFF_UPDATE_INDEX;
/* if ignore_submodules not explicitly set, check diff config */
git_diff *diff,
const char *path,
uint16_t mode,
- git_off_t size)
+ git_object_size_t size)
{
git_index_entry entry;
- if (size < 0 || size > UINT32_MAX) {
+ if (size > UINT32_MAX) {
git_error_set(GIT_ERROR_NOMEMORY, "file size overflow (for 32-bits) on '%s'", path);
return -1;
}
const git_index_entry *nitem = info->nitem;
unsigned int omode = oitem->mode;
unsigned int nmode = nitem->mode;
- bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
+ bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_WORKDIR);
bool modified_uncertain = false;
const char *matched_pathspec;
int error = 0;
/* if oids and modes match (and are valid), then file is unmodified */
} else if (git_oid_equal(&oitem->id, &nitem->id) &&
omode == nmode &&
- !git_oid_iszero(&oitem->id)) {
+ !git_oid_is_zero(&oitem->id)) {
status = GIT_DELTA_UNMODIFIED;
/* if we have an unknown OID and a workdir iterator, then check some
* circumstances that can accelerate things or need special handling
*/
- } else if (git_oid_iszero(&nitem->id) && new_is_workdir) {
+ } else if (git_oid_is_zero(&nitem->id) && new_is_workdir) {
bool use_ctime =
((diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) != 0);
git_index *index = git_iterator_index(info->new_iter);
/* if we got here and decided that the files are modified, but we
* haven't calculated the OID of the new item, then calculate it now
*/
- if (modified_uncertain && git_oid_iszero(&nitem->id)) {
+ if (modified_uncertain && git_oid_is_zero(&nitem->id)) {
const git_oid *update_check =
DIFF_FLAG_IS_SET(diff, GIT_DIFF_UPDATE_INDEX) && omode == nmode ?
&oitem->id : NULL;
return diff_delta__from_two(
diff, status, oitem, omode, nitem, nmode,
- git_oid_iszero(&noid) ? NULL : &noid, matched_pathspec);
+ git_oid_is_zero(&noid) ? NULL : &noid, matched_pathspec);
}
static bool entry_is_prefixed(
/* item contained in ignored directory, so skip over it */
return iterator_advance(&info->nitem, info->new_iter);
- else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) {
+ else if (info->new_iter->type != GIT_ITERATOR_WORKDIR) {
if (delta_type != GIT_DELTA_CONFLICTED)
delta_type = GIT_DELTA_ADDED;
}
return error;
}
-#define DIFF_FROM_ITERATORS(MAKE_FIRST, FLAGS_FIRST, MAKE_SECOND, FLAGS_SECOND) do { \
- git_iterator *a = NULL, *b = NULL; \
- char *pfx = (opts && !(opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) ? \
- git_pathspec_prefix(&opts->pathspec) : NULL; \
- git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT, \
- b_opts = GIT_ITERATOR_OPTIONS_INIT; \
- a_opts.flags = FLAGS_FIRST; \
- a_opts.start = pfx; \
- a_opts.end = pfx; \
- b_opts.flags = FLAGS_SECOND; \
- b_opts.start = pfx; \
- b_opts.end = pfx; \
- GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \
- if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) { \
- a_opts.pathlist.strings = opts->pathspec.strings; \
- a_opts.pathlist.count = opts->pathspec.count; \
- b_opts.pathlist.strings = opts->pathspec.strings; \
- b_opts.pathlist.count = opts->pathspec.count; \
- } \
- if (!error && !(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
- error = git_diff__from_iterators(&diff, repo, a, b, opts); \
- git__free(pfx); git_iterator_free(a); git_iterator_free(b); \
-} while (0)
+static int diff_prepare_iterator_opts(char **prefix, git_iterator_options *a, int aflags,
+ git_iterator_options *b, int bflags,
+ const git_diff_options *opts)
+{
+ GIT_ERROR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
+
+ *prefix = NULL;
+
+ if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) {
+ a->pathlist.strings = opts->pathspec.strings;
+ a->pathlist.count = opts->pathspec.count;
+ b->pathlist.strings = opts->pathspec.strings;
+ b->pathlist.count = opts->pathspec.count;
+ } else if (opts) {
+ *prefix = git_pathspec_prefix(&opts->pathspec);
+ GIT_ERROR_CHECK_ALLOC(prefix);
+ }
+
+ a->flags = aflags;
+ b->flags = bflags;
+ a->start = b->start = *prefix;
+ a->end = b->end = *prefix;
+
+ return 0;
+}
int git_diff_tree_to_tree(
git_diff **out,
git_tree *new_tree,
const git_diff_options *opts)
{
- git_diff *diff = NULL;
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE;
+ git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
+ b_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_iterator *a = NULL, *b = NULL;
+ git_diff *diff = NULL;
+ char *prefix = NULL;
int error = 0;
assert(out && repo);
if (opts && (opts->flags & GIT_DIFF_IGNORE_CASE) != 0)
iflag = GIT_ITERATOR_IGNORE_CASE;
- DIFF_FROM_ITERATORS(
- git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
- git_iterator_for_tree(&b, new_tree, &b_opts), iflag
- );
+ if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 ||
+ (error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
+ (error = git_iterator_for_tree(&b, new_tree, &b_opts)) < 0 ||
+ (error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
+ goto out;
- if (!error)
- *out = diff;
+ *out = diff;
+ diff = NULL;
+out:
+ git_iterator_free(a);
+ git_iterator_free(b);
+ git_diff_free(diff);
+ git__free(prefix);
return error;
}
git_index *index,
const git_diff_options *opts)
{
- git_diff *diff = NULL;
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE |
GIT_ITERATOR_INCLUDE_CONFLICTS;
+ git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
+ b_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_iterator *a = NULL, *b = NULL;
+ git_diff *diff = NULL;
+ char *prefix = NULL;
bool index_ignore_case = false;
int error = 0;
index_ignore_case = index->ignore_case;
- DIFF_FROM_ITERATORS(
- git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
- git_iterator_for_index(&b, repo, index, &b_opts), iflag
- );
+ if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, iflag, &b_opts, iflag, opts)) < 0 ||
+ (error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
+ (error = git_iterator_for_index(&b, repo, index, &b_opts)) < 0 ||
+ (error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
+ goto out;
/* if index is in case-insensitive order, re-sort deltas to match */
- if (!error && index_ignore_case)
- git_diff__set_ignore_case(diff, true);
+ if (index_ignore_case)
+ diff_set_ignore_case(diff, true);
- if (!error)
- *out = diff;
+ *out = diff;
+ diff = NULL;
+out:
+ git_iterator_free(a);
+ git_iterator_free(b);
+ git_diff_free(diff);
+ git__free(prefix);
return error;
}
git_index *index,
const git_diff_options *opts)
{
+ git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
+ b_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_iterator *a = NULL, *b = NULL;
git_diff *diff = NULL;
+ char *prefix = NULL;
int error = 0;
assert(out && repo);
if (!index && (error = diff_load_index(&index, repo)) < 0)
return error;
- DIFF_FROM_ITERATORS(
- git_iterator_for_index(&a, repo, index, &a_opts),
- GIT_ITERATOR_INCLUDE_CONFLICTS,
-
- git_iterator_for_workdir(&b, repo, index, NULL, &b_opts),
- GIT_ITERATOR_DONT_AUTOEXPAND
- );
-
- if (!error && (diff->opts.flags & GIT_DIFF_UPDATE_INDEX) != 0 &&
- ((git_diff_generated *)diff)->index_updated)
- error = git_index_write(index);
-
- if (!error)
- *out = diff;
+ if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, GIT_ITERATOR_INCLUDE_CONFLICTS,
+ &b_opts, GIT_ITERATOR_DONT_AUTOEXPAND, opts)) < 0 ||
+ (error = git_iterator_for_index(&a, repo, index, &a_opts)) < 0 ||
+ (error = git_iterator_for_workdir(&b, repo, index, NULL, &b_opts)) < 0 ||
+ (error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
+ goto out;
+
+ if ((diff->opts.flags & GIT_DIFF_UPDATE_INDEX) && ((git_diff_generated *)diff)->index_updated)
+ if ((error = git_index_write(index)) < 0)
+ goto out;
+
+ *out = diff;
+ diff = NULL;
+out:
+ git_iterator_free(a);
+ git_iterator_free(b);
+ git_diff_free(diff);
+ git__free(prefix);
return error;
}
git_tree *old_tree,
const git_diff_options *opts)
{
+ git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
+ b_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_iterator *a = NULL, *b = NULL;
git_diff *diff = NULL;
+ char *prefix = NULL;
git_index *index;
- int error = 0;
+ int error;
assert(out && repo);
*out = NULL;
- if ((error = git_repository_index__weakptr(&index, repo)))
- return error;
-
- DIFF_FROM_ITERATORS(
- git_iterator_for_tree(&a, old_tree, &a_opts), 0,
- git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts), GIT_ITERATOR_DONT_AUTOEXPAND
- );
-
- if (!error)
- *out = diff;
+ if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, 0,
+ &b_opts, GIT_ITERATOR_DONT_AUTOEXPAND, opts) < 0) ||
+ (error = git_repository_index__weakptr(&index, repo)) < 0 ||
+ (error = git_iterator_for_tree(&a, old_tree, &a_opts)) < 0 ||
+ (error = git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts)) < 0 ||
+ (error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
+ goto out;
+
+ *out = diff;
+ diff = NULL;
+out:
+ git_iterator_free(a);
+ git_iterator_free(b);
+ git_diff_free(diff);
+ git__free(prefix);
return error;
}
git_index *new_index,
const git_diff_options *opts)
{
- git_diff *diff;
- int error = 0;
+ git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT,
+ b_opts = GIT_ITERATOR_OPTIONS_INIT;
+ git_iterator *a = NULL, *b = NULL;
+ git_diff *diff = NULL;
+ char *prefix = NULL;
+ int error;
assert(out && old_index && new_index);
*out = NULL;
- DIFF_FROM_ITERATORS(
- git_iterator_for_index(&a, repo, old_index, &a_opts), GIT_ITERATOR_DONT_IGNORE_CASE,
- git_iterator_for_index(&b, repo, new_index, &b_opts), GIT_ITERATOR_DONT_IGNORE_CASE
- );
+ if ((error = diff_prepare_iterator_opts(&prefix, &a_opts, GIT_ITERATOR_DONT_IGNORE_CASE,
+ &b_opts, GIT_ITERATOR_DONT_IGNORE_CASE, opts) < 0) ||
+ (error = git_iterator_for_index(&a, repo, old_index, &a_opts)) < 0 ||
+ (error = git_iterator_for_index(&b, repo, new_index, &b_opts)) < 0 ||
+ (error = git_diff__from_iterators(&diff, repo, a, b, opts)) < 0)
+ goto out;
/* if index is in case-insensitive order, re-sort deltas to match */
- if (!error && (old_index->ignore_case || new_index->ignore_case))
- git_diff__set_ignore_case(diff, true);
+ if (old_index->ignore_case || new_index->ignore_case)
+ diff_set_ignore_case(diff, true);
- if (!error)
- *out = diff;
+ *out = diff;
+ diff = NULL;
+out:
+ git_iterator_free(a);
+ git_iterator_free(b);
+ git_diff_free(diff);
+ git__free(prefix);
return error;
}
if (i2w_icase && !icase_mismatch) {
strcomp = git__strcasecmp;
- git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__i2w_casecmp);
+ git_vector_set_cmp(&idx2wd->deltas, diff_delta_i2w_casecmp);
git_vector_sort(&idx2wd->deltas);
} else if (idx2wd != NULL) {
- git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__i2w_cmp);
+ git_vector_set_cmp(&idx2wd->deltas, diff_delta_i2w_cmp);
git_vector_sort(&idx2wd->deltas);
}
git_diff *diff,
const char *path,
uint16_t mode,
- git_off_t size);
+ git_object_size_t size);
extern int git_diff__oid_for_entry(
git_oid *out,
git_odb_free(odb);
if (!error)
- file->size = (git_off_t)len;
+ file->size = (git_object_size_t)len;
return error;
}
diff->base.patch_fn = git_patch_parsed_from_diff;
diff->base.free_fn = diff_parsed_free;
- if (git_diff_init_options(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION) < 0) {
+ if (git_diff_options_init(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION) < 0) {
git__free(diff);
return NULL;
}
diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
- git_pool_init(&diff->base.pool, 1);
-
- if (git_vector_init(&diff->patches, 0, NULL) < 0 ||
+ if (git_pool_init(&diff->base.pool, 1) < 0 ||
+ git_vector_init(&diff->patches, 0, NULL) < 0 ||
git_vector_init(&diff->base.deltas, 0, git_diff_delta__cmp) < 0) {
git_diff_free(&diff->base);
return NULL;
#include "diff.h"
#include "diff_file.h"
#include "patch_generate.h"
-#include "fileops.h"
+#include "futils.h"
#include "zstream.h"
#include "blob.h"
#include "delta.h"
if (!pi->id_strlen) {
if (!repo)
pi->id_strlen = GIT_ABBREV_DEFAULT;
- else if (git_repository__cvar(&pi->id_strlen, repo, GIT_CVAR_ABBREV) < 0)
+ else if (git_repository__configmap_lookup(&pi->id_strlen, repo, GIT_CONFIGMAP_ABBREV) < 0)
return -1;
}
}
static int diff_print_oid_range(
- git_buf *out, const git_diff_delta *delta, int id_strlen)
+ git_buf *out, const git_diff_delta *delta, int id_strlen,
+ bool print_index)
{
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id);
if (delta->old_file.mode == delta->new_file.mode) {
- git_buf_printf(out, "index %s..%s %o\n",
- start_oid, end_oid, delta->old_file.mode);
+ if (print_index)
+ git_buf_printf(out, "index %s..%s %o\n",
+ start_oid, end_oid, delta->old_file.mode);
} else {
if (delta->old_file.mode == 0)
git_buf_printf(out, "new file mode %o\n", delta->new_file.mode);
else
diff_print_modes(out, delta);
- git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
+ if (print_index)
+ git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
}
return git_buf_oom(out) ? -1 : 0;
const char *oldpath,
const char *newpath)
{
- if (git_oid_iszero(&delta->old_file.id))
+ if (git_oid_is_zero(&delta->old_file.id))
oldpath = "/dev/null";
- if (git_oid_iszero(&delta->new_file.id))
+ if (git_oid_is_zero(&delta->new_file.id))
newpath = "/dev/null";
return git_buf_printf(out, template, oldpath, newpath);
}
-int diff_delta_format_similarity_header(
+static int diff_delta_format_similarity_header(
git_buf *out,
const git_diff_delta *delta)
{
goto done;
}
+ GIT_ASSERT(delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED);
if (delta->status == GIT_DELTA_RENAMED)
type = "rename";
- else if (delta->status == GIT_DELTA_COPIED)
- type = "copy";
else
- abort();
+ type = "copy";
if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 ||
- (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
- (error = git_buf_quote(&old_path)) < 0 ||
- (error = git_buf_quote(&new_path)) < 0)
+ (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
+ (error = git_buf_quote(&old_path)) < 0 ||
+ (error = git_buf_quote(&new_path)) < 0)
goto done;
git_buf_printf(out,
static bool delta_is_unchanged(const git_diff_delta *delta)
{
- if (git_oid_iszero(&delta->old_file.id) &&
- git_oid_iszero(&delta->new_file.id))
+ if (git_oid_is_zero(&delta->old_file.id) &&
+ git_oid_is_zero(&delta->new_file.id))
return true;
if (delta->old_file.mode == GIT_FILEMODE_COMMIT ||
const git_diff_delta *delta,
const char *oldpfx,
const char *newpfx,
- int id_strlen)
+ int id_strlen,
+ bool print_index)
{
git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
bool unchanged = delta_is_unchanged(delta);
git_buf_printf(out, "diff --git %s %s\n",
old_path.ptr, new_path.ptr);
+ if (unchanged && delta->old_file.mode != delta->new_file.mode)
+ diff_print_modes(out, delta);
+
if (delta->status == GIT_DELTA_RENAMED ||
- (delta->status == GIT_DELTA_COPIED && unchanged)) {
+ (delta->status == GIT_DELTA_COPIED && unchanged)) {
if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
goto done;
}
if (!unchanged) {
- if ((error = diff_print_oid_range(out, delta, id_strlen)) < 0)
+ if ((error = diff_print_oid_range(out, delta,
+ id_strlen, print_index)) < 0)
goto done;
if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
"--- %s\n+++ %s\n", old_path.ptr, new_path.ptr);
}
- if (unchanged && delta->old_file.mode != delta->new_file.mode)
- diff_print_modes(out, delta);
-
if (git_buf_oom(out))
error = -1;
}
git_buf_putc(pi->buf, '\n');
+ if (git_buf_oom(pi->buf))
+ return -1;
+
return 0;
}
git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
int error;
- if ((error = diff_delta_format_path(
- &old_path, old_pfx, delta->old_file.path)) < 0 ||
- (error = diff_delta_format_path(
- &new_path, new_pfx, delta->new_file.path)) < 0)
+ if ((error = diff_delta_format_path(&old_path, old_pfx, delta->old_file.path)) < 0 ||
+ (error = diff_delta_format_path(&new_path, new_pfx, delta->new_file.path)) < 0 ||
+ (error = diff_delta_format_with_paths(pi->buf, delta, "Binary files %s and %s differ\n",
+ old_path.ptr, new_path.ptr)) < 0)
goto done;
pi->line.num_lines = 1;
- error = diff_delta_format_with_paths(
- pi->buf, delta, "Binary files %s and %s differ\n",
- old_path.ptr, new_path.ptr);
done:
git_buf_dispose(&old_path);
git_buf_dispose(&new_path);
-
return error;
}
pi->line.num_lines++;
if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
- binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
- (error = format_binary(pi, binary->old_file.type, binary->old_file.data,
- binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
-
+ binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
+ (error = format_binary(pi, binary->old_file.type, binary->old_file.data,
+ binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
if (error == GIT_EBUFS) {
git_error_clear();
git_buf_truncate(pi->buf, pre_binary_size);
(pi->flags & GIT_DIFF_FORCE_BINARY);
bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
int id_strlen = pi->id_strlen;
+ bool print_index = (pi->format != GIT_DIFF_FORMAT_PATCH_ID);
if (binary && show_binary)
id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev :
GIT_UNUSED(progress);
if (S_ISDIR(delta->new_file.mode) ||
- delta->status == GIT_DELTA_UNMODIFIED ||
- delta->status == GIT_DELTA_IGNORED ||
- delta->status == GIT_DELTA_UNREADABLE ||
- (delta->status == GIT_DELTA_UNTRACKED &&
+ delta->status == GIT_DELTA_UNMODIFIED ||
+ delta->status == GIT_DELTA_IGNORED ||
+ delta->status == GIT_DELTA_UNREADABLE ||
+ (delta->status == GIT_DELTA_UNTRACKED &&
(pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0))
return 0;
- if ((error = git_diff_delta__format_file_header(
- pi->buf, delta, oldpfx, newpfx, id_strlen)) < 0)
+ if ((error = git_diff_delta__format_file_header(pi->buf, delta, oldpfx, newpfx,
+ id_strlen, print_index)) < 0)
return error;
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
print_hunk = diff_print_patch_hunk;
print_line = diff_print_patch_line;
break;
+ case GIT_DIFF_FORMAT_PATCH_ID:
+ print_file = diff_print_patch_file;
+ print_binary = diff_print_patch_binary;
+ print_line = diff_print_patch_line;
+ break;
case GIT_DIFF_FORMAT_PATCH_HEADER:
print_file = diff_print_patch_file;
break;
return -1;
}
- if (!(error = diff_print_info_init_fromdiff(
- &pi, &buf, diff, format, print_cb, payload))) {
- error = git_diff_foreach(
- diff, print_file, print_binary, print_hunk, print_line, &pi);
+ if ((error = diff_print_info_init_fromdiff(&pi, &buf, diff, format, print_cb, payload)) < 0)
+ goto out;
- if (error) /* make sure error message is set */
- git_error_set_after_callback_function(error, "git_diff_print");
+ if ((error = git_diff_foreach(diff, print_file, print_binary, print_hunk, print_line, &pi)) != 0) {
+ git_error_set_after_callback_function(error, "git_diff_print");
+ goto out;
}
+out:
git_buf_dispose(&buf);
-
return error;
}
}
if (line->origin == GIT_DIFF_LINE_ADDITION ||
- line->origin == GIT_DIFF_LINE_DELETION ||
- line->origin == GIT_DIFF_LINE_CONTEXT)
+ line->origin == GIT_DIFF_LINE_DELETION ||
+ line->origin == GIT_DIFF_LINE_CONTEXT)
git_buf_putc(output, line->origin);
return git_buf_put(output, line->content, line->content_len);
void *payload)
{
FILE *fp = payload ? payload : stdout;
+ int error;
- GIT_UNUSED(delta); GIT_UNUSED(hunk);
+ GIT_UNUSED(delta);
+ GIT_UNUSED(hunk);
if (line->origin == GIT_DIFF_LINE_CONTEXT ||
- line->origin == GIT_DIFF_LINE_ADDITION ||
- line->origin == GIT_DIFF_LINE_DELETION)
- fputc(line->origin, fp);
- fwrite(line->content, 1, line->content_len, fp);
+ line->origin == GIT_DIFF_LINE_ADDITION ||
+ line->origin == GIT_DIFF_LINE_DELETION) {
+ while ((error = fputc(line->origin, fp)) == EINTR)
+ continue;
+ if (error) {
+ git_error_set(GIT_ERROR_OS, "could not write status");
+ return -1;
+ }
+ }
+
+ if (fwrite(line->content, line->content_len, 1, fp) != 1) {
+ git_error_set(GIT_ERROR_OS, "could not write line");
+ return -1;
+ }
+
return 0;
}
{
assert(out && diff);
git_buf_sanitize(out);
- return git_diff_print(
- diff, format, git_diff_print_callback__to_buf, out);
+ return git_diff_print(diff, format, git_diff_print_callback__to_buf, out);
}
/* print a git_patch to an output callback */
git_diff_line_cb print_cb,
void *payload)
{
- int error;
git_buf temp = GIT_BUF_INIT;
diff_print_info pi;
+ int error;
assert(patch && print_cb);
- if (!(error = diff_print_info_init_frompatch(
- &pi, &temp, patch,
- GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
- {
- error = git_patch__invoke_callbacks(
- patch,
- diff_print_patch_file, diff_print_patch_binary,
- diff_print_patch_hunk, diff_print_patch_line,
- &pi);
-
- if (error) /* make sure error message is set */
- git_error_set_after_callback_function(error, "git_patch_print");
+ if ((error = diff_print_info_init_frompatch(&pi, &temp, patch,
+ GIT_DIFF_FORMAT_PATCH, print_cb, payload)) < 0)
+ goto out;
+
+ if ((error = git_patch__invoke_callbacks(patch, diff_print_patch_file, diff_print_patch_binary,
+ diff_print_patch_hunk, diff_print_patch_line, &pi)) < 0) {
+ git_error_set_after_callback_function(error, "git_patch_print");
+ goto out;
}
+out:
git_buf_dispose(&temp);
-
return error;
}
return count;
}
-int git_diff_file_stats__full_to_buf(
+static int diff_file_stats_full_to_buf(
git_buf *out,
const git_diff_delta *delta,
const diff_file_stats *filestat,
const git_diff_stats *stats,
size_t width)
{
- const char *old_path = NULL, *new_path = NULL;
+ const char *old_path = NULL, *new_path = NULL, *adddel_path = NULL;
size_t padding;
- git_off_t old_size, new_size;
+ git_object_size_t old_size, new_size;
old_path = delta->old_file.path;
new_path = delta->new_file.path;
old_size = delta->old_file.size;
new_size = delta->new_file.size;
- if (strcmp(old_path, new_path) != 0) {
+ if (old_path && new_path && strcmp(old_path, new_path) != 0) {
size_t common_dirlen;
int error;
if (error < 0)
goto on_error;
} else {
- if (git_buf_printf(out, " %s", old_path) < 0)
+ adddel_path = new_path ? new_path : old_path;
+ if (git_buf_printf(out, " %s", adddel_path) < 0)
goto on_error;
- padding = stats->max_name - strlen(old_path);
+ padding = stats->max_name - strlen(adddel_path);
if (stats->renames > 0)
padding += strlen(DIFF_RENAME_FILE_SEPARATOR);
return (git_buf_oom(out) ? -1 : 0);
}
-int git_diff_file_stats__number_to_buf(
+static int diff_file_stats_number_to_buf(
git_buf *out,
const git_diff_delta *delta,
const diff_file_stats *filestats)
return error;
}
-int git_diff_file_stats__summary_to_buf(
+static int diff_file_stats_summary_to_buf(
git_buf *out,
const git_diff_delta *delta)
{
/* TODO ugh */
namelen = strlen(delta->new_file.path);
- if (strcmp(delta->old_file.path, delta->new_file.path) != 0) {
+ if (delta->old_file.path && strcmp(delta->old_file.path, delta->new_file.path) != 0) {
namelen += strlen(delta->old_file.path);
stats->renames++;
}
if ((delta = git_diff_get_delta(stats->diff, i)) == NULL)
continue;
- error = git_diff_file_stats__number_to_buf(
+ error = diff_file_stats_number_to_buf(
out, delta, &stats->filestats[i]);
if (error < 0)
return error;
if ((delta = git_diff_get_delta(stats->diff, i)) == NULL)
continue;
- error = git_diff_file_stats__full_to_buf(
+ error = diff_file_stats_full_to_buf(
out, delta, &stats->filestats[i], stats, width);
if (error < 0)
return error;
if ((delta = git_diff_get_delta(stats->diff, i)) == NULL)
continue;
- error = git_diff_file_stats__summary_to_buf(out, delta);
+ error = diff_file_stats_summary_to_buf(out, delta);
if (error < 0)
return error;
}
#include "diff.h"
#include "diff_generate.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
#include "config.h"
git_diff_delta *git_diff__delta_dup(
return -1;
}
- if (git_vector_init(&onto_new, onto->deltas.length, git_diff_delta__cmp) < 0)
+ if (git_vector_init(&onto_new, onto->deltas.length, git_diff_delta__cmp) < 0 ||
+ git_pool_init(&onto_pool, 1) < 0)
return -1;
- git_pool_init(&onto_pool, 1);
-
for (i = 0, j = 0; i < onto->deltas.length || j < from->deltas.length; ) {
git_diff_delta *o = GIT_VECTOR_GET(&onto->deltas, i);
const git_diff_delta *f = GIT_VECTOR_GET(&from->deltas, j);
if (insert_delete_side_of_split(diff, &onto, delta) < 0)
goto on_error;
- if (diff->new_src == GIT_ITERATOR_TYPE_WORKDIR)
+ if (diff->new_src == GIT_ITERATOR_WORKDIR)
delta->status = GIT_DELTA_UNTRACKED;
else
delta->status = GIT_DELTA_ADDED;
typedef struct {
size_t idx;
- git_iterator_type_t src;
+ git_iterator_t src;
git_repository *repo;
git_diff_file *file;
git_buf data;
info->blob = NULL;
git_buf_init(&info->data, 0);
- if (info->file->size > 0 || info->src == GIT_ITERATOR_TYPE_WORKDIR)
+ if (info->file->size > 0 || info->src == GIT_ITERATOR_WORKDIR)
return 0;
return git_diff_file__resolve_zero_size(
int error = 0;
git_diff_file *file = info->file;
- if (info->src == GIT_ITERATOR_TYPE_WORKDIR) {
+ if (info->src == GIT_ITERATOR_WORKDIR) {
if ((error = git_buf_joinpath(
&info->data, git_repository_workdir(info->repo), file->path)) < 0)
return error;
if (file->size != git_blob_rawsize(info->blob))
file->size = git_blob_rawsize(info->blob);
- sz = (size_t)(git__is_sizet(file->size) ? file->size : -1);
+ sz = git__is_sizet(file->size) ? (size_t)file->size : (size_t)-1;
error = opts->metric->buffer_signature(
&cache[info->idx], info->file,
/* if exact match is requested, force calculation of missing OIDs now */
if (exact_match) {
- if (git_oid_iszero(&a_file->id) &&
- diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
+ if (git_oid_is_zero(&a_file->id) &&
+ diff->old_src == GIT_ITERATOR_WORKDIR &&
!git_diff__oid_for_file(&a_file->id,
diff, a_file->path, a_file->mode, a_file->size))
a_file->flags |= GIT_DIFF_FLAG_VALID_ID;
- if (git_oid_iszero(&b_file->id) &&
- diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
+ if (git_oid_is_zero(&b_file->id) &&
+ diff->new_src == GIT_ITERATOR_WORKDIR &&
!git_diff__oid_for_file(&b_file->id,
diff, b_file->path, b_file->mode, b_file->size))
b_file->flags |= GIT_DIFF_FLAG_VALID_ID;
delta_make_rename(tgt, src, best_match->similarity);
- src->status = (diff->new_src == GIT_ITERATOR_TYPE_WORKDIR) ?
+ src->status = (diff->new_src == GIT_ITERATOR_WORKDIR) ?
GIT_DELTA_UNTRACKED : GIT_DELTA_ADDED;
src->nfiles = 1;
memset(&src->old_file, 0, sizeof(src->old_file));
GIT_GLOBAL->last_error = &g_git_oom_error;
}
-void git_error_set(int error_class, const char *string, ...)
+void git_error_set(int error_class, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ git_error_vset(error_class, fmt, ap);
+ va_end(ap);
+}
+
+void git_error_vset(int error_class, const char *fmt, va_list ap)
{
- va_list arglist;
#ifdef GIT_WIN32
DWORD win32_error_code = (error_class == GIT_ERROR_OS) ? GetLastError() : 0;
#endif
git_buf *buf = &GIT_GLOBAL->error_buf;
git_buf_clear(buf);
- if (string) {
- va_start(arglist, string);
- git_buf_vprintf(buf, string, arglist);
- va_end(arglist);
-
+ if (fmt) {
+ git_buf_vprintf(buf, fmt, ap);
if (error_class == GIT_ERROR_OS)
git_buf_PUTS(buf, ": ");
}
set_error_from_buffer(error_class);
}
-void git_error_set_str(int error_class, const char *string)
+int git_error_set_str(int error_class, const char *string)
{
git_buf *buf = &GIT_GLOBAL->error_buf;
assert(string);
- if (!string)
- return;
+ if (!string) {
+ git_error_set(GIT_ERROR_INVALID, "unspecified caller error");
+ return -1;
+ }
git_buf_clear(buf);
git_buf_puts(buf, string);
- if (!git_buf_oom(buf))
- set_error_from_buffer(error_class);
-}
-
-int git_error_set_regex(const regex_t *regex, int error_code)
-{
- char error_buf[1024];
- assert(error_code);
+ if (git_buf_oom(buf))
+ return -1;
- regerror(error_code, regex, error_buf, sizeof(error_buf));
- git_error_set_str(GIT_ERROR_REGEX, error_buf);
-
- if (error_code == REG_NOMATCH)
- return GIT_ENOTFOUND;
-
- return GIT_EINVALIDSPEC;
+ set_error_from_buffer(error_class);
+ return 0;
}
void git_error_clear(void)
/* Deprecated error values and functions */
+#ifndef GIT_DEPRECATE_HARD
const git_error *giterr_last(void)
{
return git_error_last();
{
git_error_set_oom();
}
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_errors_h__
+#define INCLUDE_errors_h__
+
+#include "common.h"
+
+/*
+ * Set the error message for this thread, formatting as needed.
+ */
+void git_error_set(int error_class, const char *fmt, ...) GIT_FORMAT_PRINTF(2, 3);
+void git_error_vset(int error_class, const char *fmt, va_list ap);
+
+/**
+ * Set error message for user callback if needed.
+ *
+ * If the error code in non-zero and no error message is set, this
+ * sets a generic error message.
+ *
+ * @return This always returns the `error_code` parameter.
+ */
+GIT_INLINE(int) git_error_set_after_callback_function(
+ int error_code, const char *action)
+{
+ if (error_code) {
+ const git_error *e = git_error_last();
+ if (!e || !e->message)
+ git_error_set(e ? e->klass : GIT_ERROR_CALLBACK,
+ "%s callback returned %d", action, error_code);
+ }
+ return error_code;
+}
+
+#ifdef GIT_WIN32
+#define git_error_set_after_callback(code) \
+ git_error_set_after_callback_function((code), __FUNCTION__)
+#else
+#define git_error_set_after_callback(code) \
+ git_error_set_after_callback_function((code), __func__)
+#endif
+
+/**
+ * Gets the system error code for this thread.
+ */
+int git_error_system_last(void);
+
+/**
+ * Sets the system error code for this thread.
+ */
+void git_error_system_set(int code);
+
+/**
+ * Structure to preserve libgit2 error state
+ */
+typedef struct {
+ int error_code;
+ unsigned int oom : 1;
+ git_error error_msg;
+} git_error_state;
+
+/**
+ * Capture current error state to restore later, returning error code.
+ * If `error_code` is zero, this does not clear the current error state.
+ * You must either restore this error state, or free it.
+ */
+extern int git_error_state_capture(git_error_state *state, int error_code);
+
+/**
+ * Restore error state to a previous value, returning saved error code.
+ */
+extern int git_error_state_restore(git_error_state *state);
+
+/** Free an error state. */
+extern void git_error_state_free(git_error_state *state);
+
+#endif
#cmakedefine GIT_USE_STAT_MTIMESPEC 1
#cmakedefine GIT_USE_STAT_MTIME_NSEC 1
#cmakedefine GIT_USE_FUTIMENS 1
-#cmakedefine GIT_USE_REGCOMP_L 1
+
+#cmakedefine GIT_REGEX_REGCOMP_L
+#cmakedefine GIT_REGEX_REGCOMP
+#cmakedefine GIT_REGEX_PCRE
+#cmakedefine GIT_REGEX_PCRE2
+#cmakedefine GIT_REGEX_BUILTIN 1
#cmakedefine GIT_SSH 1
#cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1
+#cmakedefine GIT_NTLM 1
#cmakedefine GIT_GSSAPI 1
-#cmakedefine GIT_WINHTTP 1
+#cmakedefine GIT_GSSFRAMEWORK 1
+#cmakedefine GIT_WINHTTP 1
#cmakedefine GIT_HTTPS 1
#cmakedefine GIT_OPENSSL 1
#cmakedefine GIT_SECURE_TRANSPORT 1
int git_fetch_download_pack(git_remote *remote, const git_remote_callbacks *callbacks)
{
git_transport *t = remote->transport;
- git_transfer_progress_cb progress = NULL;
+ git_indexer_progress_cb progress = NULL;
void *payload = NULL;
if (!remote->need_pack)
return t->download_pack(t, remote->repo, &remote->stats, progress, payload);
}
-int git_fetch_init_options(git_fetch_options *opts, unsigned int version)
+int git_fetch_options_init(git_fetch_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_fetch_options, GIT_FETCH_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_fetch_init_options(git_fetch_options *opts, unsigned int version)
+{
+ return git_fetch_options_init(opts, version);
+}
+#endif
#include "git2/oid.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#include "filebuf.h"
#include "refs.h"
+#include "net.h"
#include "repository.h"
int git_fetchhead_ref_cmp(const void *a, const void *b)
return 0;
}
+static char *sanitized_remote_url(const char *remote_url)
+{
+ git_net_url url = GIT_NET_URL_INIT;
+ char *sanitized = NULL;
+ int error;
+
+ if (git_net_url_parse(&url, remote_url) == 0) {
+ git_buf buf = GIT_BUF_INIT;
+
+ git__free(url.username);
+ git__free(url.password);
+ url.username = url.password = NULL;
+
+ if ((error = git_net_url_fmt(&buf, &url)) < 0)
+ goto fallback;
+
+ sanitized = git_buf_detach(&buf);
+ }
+
+fallback:
+ if (!sanitized)
+ sanitized = git__strdup(remote_url);
+
+ git_net_url_dispose(&url);
+ return sanitized;
+}
+
int git_fetchhead_ref_create(
git_fetchhead_ref **out,
git_oid *oid,
git_oid_cpy(&fetchhead_ref->oid, oid);
fetchhead_ref->is_merge = is_merge;
- if (ref_name)
+ if (ref_name) {
fetchhead_ref->ref_name = git__strdup(ref_name);
+ GIT_ERROR_CHECK_ALLOC(fetchhead_ref->ref_name);
+ }
- if (remote_url)
- fetchhead_ref->remote_url = git__strdup(remote_url);
+ if (remote_url) {
+ fetchhead_ref->remote_url = sanitized_remote_url(remote_url);
+ GIT_ERROR_CHECK_ALLOC(fetchhead_ref->remote_url);
+ }
*out = fetchhead_ref;
#include "filebuf.h"
-#include "fileops.h"
+#include "futils.h"
static const size_t WRITE_BUFFER_SIZE = (4096 * 2);
static int lock_file(git_filebuf *file, int flags, mode_t mode)
{
if (git_path_exists(file->path_lock) == true) {
- if (flags & GIT_FILEBUF_FORCE)
- p_unlink(file->path_lock);
- else {
- git_error_clear(); /* actual OS error code just confuses */
- git_error_set(GIT_ERROR_OS,
- "failed to lock file '%s' for writing", file->path_lock);
- return GIT_ELOCKED;
- }
+ git_error_clear(); /* actual OS error code just confuses */
+ git_error_set(GIT_ERROR_OS,
+ "failed to lock file '%s' for writing", file->path_lock);
+ return GIT_ELOCKED;
}
/* create path to the file buffer is required */
- if (flags & GIT_FILEBUF_FORCE) {
+ if (flags & GIT_FILEBUF_CREATE_LEADING_DIRS) {
/* XXX: Should dirmode here be configurable? Or is 0777 always fine? */
file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, mode);
} else {
#include "common.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include <zlib.h>
#define GIT_FILEBUF_HASH_CONTENTS (1 << 0)
#define GIT_FILEBUF_APPEND (1 << 2)
-#define GIT_FILEBUF_FORCE (1 << 3)
+#define GIT_FILEBUF_CREATE_LEADING_DIRS (1 << 3)
#define GIT_FILEBUF_TEMPORARY (1 << 4)
#define GIT_FILEBUF_DO_NOT_BUFFER (1 << 5)
#define GIT_FILEBUF_FSYNC (1 << 6)
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "fileops.h"
-
-#include "global.h"
-#include "strmap.h"
-#include <ctype.h>
-#if GIT_WIN32
-#include "win32/findfile.h"
-#endif
-
-int git_futils_mkpath2file(const char *file_path, const mode_t mode)
-{
- return git_futils_mkdir(
- file_path, mode,
- GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
-}
-
-int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode)
-{
- int fd;
- mode_t mask;
-
- p_umask(mask = p_umask(0));
-
- git_buf_sets(path_out, filename);
- git_buf_puts(path_out, "_git2_XXXXXX");
-
- if (git_buf_oom(path_out))
- return -1;
-
- if ((fd = p_mkstemp(path_out->ptr)) < 0) {
- git_error_set(GIT_ERROR_OS,
- "failed to create temporary file '%s'", path_out->ptr);
- return -1;
- }
-
- if (p_chmod(path_out->ptr, (mode & ~mask))) {
- git_error_set(GIT_ERROR_OS,
- "failed to set permissions on file '%s'", path_out->ptr);
- return -1;
- }
-
- return fd;
-}
-
-int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode)
-{
- int fd;
-
- if (git_futils_mkpath2file(path, dirmode) < 0)
- return -1;
-
- fd = p_creat(path, mode);
- if (fd < 0) {
- git_error_set(GIT_ERROR_OS, "failed to create file '%s'", path);
- return -1;
- }
-
- return fd;
-}
-
-int git_futils_creat_locked(const char *path, const mode_t mode)
-{
- int fd = p_open(path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC,
- mode);
-
- if (fd < 0) {
- int error = errno;
- git_error_set(GIT_ERROR_OS, "failed to create locked file '%s'", path);
- switch (error) {
- case EEXIST:
- return GIT_ELOCKED;
- case ENOENT:
- return GIT_ENOTFOUND;
- default:
- return -1;
- }
- }
-
- return fd;
-}
-
-int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode)
-{
- if (git_futils_mkpath2file(path, dirmode) < 0)
- return -1;
-
- return git_futils_creat_locked(path, mode);
-}
-
-int git_futils_open_ro(const char *path)
-{
- int fd = p_open(path, O_RDONLY);
- if (fd < 0)
- return git_path_set_error(errno, path, "open");
- return fd;
-}
-
-int git_futils_truncate(const char *path, int mode)
-{
- int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
- if (fd < 0)
- return git_path_set_error(errno, path, "open");
-
- close(fd);
- return 0;
-}
-
-git_off_t git_futils_filesize(git_file fd)
-{
- struct stat sb;
-
- if (p_fstat(fd, &sb)) {
- git_error_set(GIT_ERROR_OS, "failed to stat file descriptor");
- return -1;
- }
-
- return sb.st_size;
-}
-
-mode_t git_futils_canonical_mode(mode_t raw_mode)
-{
- if (S_ISREG(raw_mode))
- return S_IFREG | GIT_PERMS_CANONICAL(raw_mode);
- else if (S_ISLNK(raw_mode))
- return S_IFLNK;
- else if (S_ISGITLINK(raw_mode))
- return S_IFGITLINK;
- else if (S_ISDIR(raw_mode))
- return S_IFDIR;
- else
- return 0;
-}
-
-int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
-{
- ssize_t read_size = 0;
- size_t alloc_len;
-
- git_buf_clear(buf);
-
- if (!git__is_ssizet(len)) {
- git_error_set(GIT_ERROR_INVALID, "read too large");
- return -1;
- }
-
- GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
- if (git_buf_grow(buf, alloc_len) < 0)
- return -1;
-
- /* p_read loops internally to read len bytes */
- read_size = p_read(fd, buf->ptr, len);
-
- if (read_size != (ssize_t)len) {
- git_error_set(GIT_ERROR_OS, "failed to read descriptor");
- git_buf_dispose(buf);
- return -1;
- }
-
- buf->ptr[read_size] = '\0';
- buf->size = read_size;
-
- return 0;
-}
-
-int git_futils_readbuffer_updated(
- git_buf *out, const char *path, git_oid *checksum, int *updated)
-{
- int error;
- git_file fd;
- struct stat st;
- git_buf buf = GIT_BUF_INIT;
- git_oid checksum_new;
-
- assert(out && path && *path);
-
- if (updated != NULL)
- *updated = 0;
-
- if (p_stat(path, &st) < 0)
- return git_path_set_error(errno, path, "stat");
-
-
- if (S_ISDIR(st.st_mode)) {
- git_error_set(GIT_ERROR_INVALID, "requested file is a directory");
- return GIT_ENOTFOUND;
- }
-
- if (!git__is_sizet(st.st_size+1)) {
- git_error_set(GIT_ERROR_OS, "invalid regular file stat for '%s'", path);
- return -1;
- }
-
- if ((fd = git_futils_open_ro(path)) < 0)
- return fd;
-
- if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) {
- p_close(fd);
- return -1;
- }
-
- p_close(fd);
-
- if (checksum) {
- if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) {
- git_buf_dispose(&buf);
- return error;
- }
-
- /*
- * If we were given a checksum, we only want to use it if it's different
- */
- if (!git_oid__cmp(checksum, &checksum_new)) {
- git_buf_dispose(&buf);
- if (updated)
- *updated = 0;
-
- return 0;
- }
-
- git_oid_cpy(checksum, &checksum_new);
- }
-
- /*
- * If we're here, the file did change, or the user didn't have an old version
- */
- if (updated != NULL)
- *updated = 1;
-
- git_buf_swap(out, &buf);
- git_buf_dispose(&buf);
-
- return 0;
-}
-
-int git_futils_readbuffer(git_buf *buf, const char *path)
-{
- return git_futils_readbuffer_updated(buf, path, NULL, NULL);
-}
-
-int git_futils_writebuffer(
- const git_buf *buf, const char *path, int flags, mode_t mode)
-{
- int fd, do_fsync = 0, error = 0;
-
- if (!flags)
- flags = O_CREAT | O_TRUNC | O_WRONLY;
-
- if ((flags & O_FSYNC) != 0)
- do_fsync = 1;
-
- flags &= ~O_FSYNC;
-
- if (!mode)
- mode = GIT_FILEMODE_BLOB;
-
- if ((fd = p_open(path, flags, mode)) < 0) {
- git_error_set(GIT_ERROR_OS, "could not open '%s' for writing", path);
- return fd;
- }
-
- if ((error = p_write(fd, git_buf_cstr(buf), git_buf_len(buf))) < 0) {
- git_error_set(GIT_ERROR_OS, "could not write to '%s'", path);
- (void)p_close(fd);
- return error;
- }
-
- if (do_fsync && (error = p_fsync(fd)) < 0) {
- git_error_set(GIT_ERROR_OS, "could not fsync '%s'", path);
- p_close(fd);
- return error;
- }
-
- if ((error = p_close(fd)) < 0) {
- git_error_set(GIT_ERROR_OS, "error while closing '%s'", path);
- return error;
- }
-
- if (do_fsync && (flags & O_CREAT))
- error = git_futils_fsync_parent(path);
-
- return error;
-}
-
-int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
-{
- if (git_futils_mkpath2file(to, dirmode) < 0)
- return -1;
-
- if (p_rename(from, to) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to rename '%s' to '%s'", from, to);
- return -1;
- }
-
- return 0;
-}
-
-int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
-{
- return p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin);
-}
-
-int git_futils_mmap_ro_file(git_map *out, const char *path)
-{
- git_file fd = git_futils_open_ro(path);
- git_off_t len;
- int result;
-
- if (fd < 0)
- return fd;
-
- if ((len = git_futils_filesize(fd)) < 0) {
- result = -1;
- goto out;
- }
-
- if (!git__is_sizet(len)) {
- git_error_set(GIT_ERROR_OS, "file `%s` too large to mmap", path);
- result = -1;
- goto out;
- }
-
- result = git_futils_mmap_ro(out, fd, 0, (size_t)len);
-out:
- p_close(fd);
- return result;
-}
-
-void git_futils_mmap_free(git_map *out)
-{
- p_munmap(out);
-}
-
-GIT_INLINE(int) mkdir_validate_dir(
- const char *path,
- struct stat *st,
- mode_t mode,
- uint32_t flags,
- struct git_futils_mkdir_options *opts)
-{
- /* with exclusive create, existing dir is an error */
- if ((flags & GIT_MKDIR_EXCL) != 0) {
- git_error_set(GIT_ERROR_FILESYSTEM,
- "failed to make directory '%s': directory exists", path);
- return GIT_EEXISTS;
- }
-
- if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) ||
- (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) {
- if (p_unlink(path) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to remove %s '%s'",
- S_ISLNK(st->st_mode) ? "symlink" : "file", path);
- return GIT_EEXISTS;
- }
-
- opts->perfdata.mkdir_calls++;
-
- if (p_mkdir(path, mode) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path);
- return GIT_EEXISTS;
- }
- }
-
- else if (S_ISLNK(st->st_mode)) {
- /* Re-stat the target, make sure it's a directory */
- opts->perfdata.stat_calls++;
-
- if (p_stat(path, st) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path);
- return GIT_EEXISTS;
- }
- }
-
- else if (!S_ISDIR(st->st_mode)) {
- git_error_set(GIT_ERROR_FILESYSTEM,
- "failed to make directory '%s': directory exists", path);
- return GIT_EEXISTS;
- }
-
- return 0;
-}
-
-GIT_INLINE(int) mkdir_validate_mode(
- const char *path,
- struct stat *st,
- bool terminal_path,
- mode_t mode,
- uint32_t flags,
- struct git_futils_mkdir_options *opts)
-{
- if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) ||
- (flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) {
-
- opts->perfdata.chmod_calls++;
-
- if (p_chmod(path, mode) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to set permissions on '%s'", path);
- return -1;
- }
- }
-
- return 0;
-}
-
-GIT_INLINE(int) mkdir_canonicalize(
- git_buf *path,
- uint32_t flags)
-{
- ssize_t root_len;
-
- if (path->size == 0) {
- git_error_set(GIT_ERROR_OS, "attempt to create empty path");
- return -1;
- }
-
- /* Trim trailing slashes (except the root) */
- if ((root_len = git_path_root(path->ptr)) < 0)
- root_len = 0;
- else
- root_len++;
-
- while (path->size > (size_t)root_len && path->ptr[path->size - 1] == '/')
- path->ptr[--path->size] = '\0';
-
- /* if we are not supposed to made the last element, truncate it */
- if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
- git_path_dirname_r(path, path->ptr);
- flags |= GIT_MKDIR_SKIP_LAST;
- }
- if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
- git_path_dirname_r(path, path->ptr);
- }
-
- /* We were either given the root path (or trimmed it to
- * the root), we don't have anything to do.
- */
- if (path->size <= (size_t)root_len)
- git_buf_clear(path);
-
- return 0;
-}
-
-int git_futils_mkdir(
- const char *path,
- mode_t mode,
- uint32_t flags)
-{
- git_buf make_path = GIT_BUF_INIT, parent_path = GIT_BUF_INIT;
- const char *relative;
- struct git_futils_mkdir_options opts = { 0 };
- struct stat st;
- size_t depth = 0;
- int len = 0, root_len, error;
-
- if ((error = git_buf_puts(&make_path, path)) < 0 ||
- (error = mkdir_canonicalize(&make_path, flags)) < 0 ||
- (error = git_buf_puts(&parent_path, make_path.ptr)) < 0 ||
- make_path.size == 0)
- goto done;
-
- root_len = git_path_root(make_path.ptr);
-
- /* find the first parent directory that exists. this will be used
- * as the base to dirname_relative.
- */
- for (relative = make_path.ptr; parent_path.size; ) {
- error = p_lstat(parent_path.ptr, &st);
-
- if (error == 0) {
- break;
- } else if (errno != ENOENT) {
- git_error_set(GIT_ERROR_OS, "failed to stat '%s'", parent_path.ptr);
- goto done;
- }
-
- depth++;
-
- /* examine the parent of the current path */
- if ((len = git_path_dirname_r(&parent_path, parent_path.ptr)) < 0) {
- error = len;
- goto done;
- }
-
- assert(len);
-
- /*
- * We've walked all the given path's parents and it's either relative
- * (the parent is simply '.') or rooted (the length is less than or
- * equal to length of the root path). The path may be less than the
- * root path length on Windows, where `C:` == `C:/`.
- */
- if ((len == 1 && parent_path.ptr[0] == '.') || len <= root_len) {
- relative = make_path.ptr;
- break;
- }
-
- relative = make_path.ptr + len + 1;
-
- /* not recursive? just make this directory relative to its parent. */
- if ((flags & GIT_MKDIR_PATH) == 0)
- break;
- }
-
- /* we found an item at the location we're trying to create,
- * validate it.
- */
- if (depth == 0) {
- error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts);
-
- if (!error)
- error = mkdir_validate_mode(
- make_path.ptr, &st, true, mode, flags, &opts);
-
- goto done;
- }
-
- /* we already took `SKIP_LAST` and `SKIP_LAST2` into account when
- * canonicalizing `make_path`.
- */
- flags &= ~(GIT_MKDIR_SKIP_LAST2 | GIT_MKDIR_SKIP_LAST);
-
- error = git_futils_mkdir_relative(relative,
- parent_path.size ? parent_path.ptr : NULL, mode, flags, &opts);
-
-done:
- git_buf_dispose(&make_path);
- git_buf_dispose(&parent_path);
- return error;
-}
-
-int git_futils_mkdir_r(const char *path, const mode_t mode)
-{
- return git_futils_mkdir(path, mode, GIT_MKDIR_PATH);
-}
-
-int git_futils_mkdir_relative(
- const char *relative_path,
- const char *base,
- mode_t mode,
- uint32_t flags,
- struct git_futils_mkdir_options *opts)
-{
- git_buf make_path = GIT_BUF_INIT;
- ssize_t root = 0, min_root_len;
- char lastch = '/', *tail;
- struct stat st;
- struct git_futils_mkdir_options empty_opts = {0};
- int error;
-
- if (!opts)
- opts = &empty_opts;
-
- /* build path and find "root" where we should start calling mkdir */
- if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0)
- return -1;
-
- if ((error = mkdir_canonicalize(&make_path, flags)) < 0 ||
- make_path.size == 0)
- goto done;
-
- /* if we are not supposed to make the whole path, reset root */
- if ((flags & GIT_MKDIR_PATH) == 0)
- root = git_buf_rfind(&make_path, '/');
-
- /* advance root past drive name or network mount prefix */
- min_root_len = git_path_root(make_path.ptr);
- if (root < min_root_len)
- root = min_root_len;
- while (root >= 0 && make_path.ptr[root] == '/')
- ++root;
-
- /* clip root to make_path length */
- if (root > (ssize_t)make_path.size)
- root = (ssize_t)make_path.size; /* i.e. NUL byte of string */
- if (root < 0)
- root = 0;
-
- /* walk down tail of path making each directory */
- for (tail = &make_path.ptr[root]; *tail; *tail = lastch) {
- bool mkdir_attempted = false;
-
- /* advance tail to include next path component */
- while (*tail == '/')
- tail++;
- while (*tail && *tail != '/')
- tail++;
-
- /* truncate path at next component */
- lastch = *tail;
- *tail = '\0';
- st.st_mode = 0;
-
- if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr))
- continue;
-
- /* See what's going on with this path component */
- opts->perfdata.stat_calls++;
-
-retry_lstat:
- if (p_lstat(make_path.ptr, &st) < 0) {
- if (mkdir_attempted || errno != ENOENT) {
- git_error_set(GIT_ERROR_OS, "cannot access component in path '%s'", make_path.ptr);
- error = -1;
- goto done;
- }
-
- git_error_clear();
- opts->perfdata.mkdir_calls++;
- mkdir_attempted = true;
- if (p_mkdir(make_path.ptr, mode) < 0) {
- if (errno == EEXIST)
- goto retry_lstat;
- git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", make_path.ptr);
- error = -1;
- goto done;
- }
- } else {
- if ((error = mkdir_validate_dir(
- make_path.ptr, &st, mode, flags, opts)) < 0)
- goto done;
- }
-
- /* chmod if requested and necessary */
- if ((error = mkdir_validate_mode(
- make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0)
- goto done;
-
- if (opts->dir_map && opts->pool) {
- char *cache_path;
- size_t alloc_size;
-
- GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1);
- if (!git__is_uint32(alloc_size))
- return -1;
- cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size);
- GIT_ERROR_CHECK_ALLOC(cache_path);
-
- memcpy(cache_path, make_path.ptr, make_path.size + 1);
-
- git_strmap_insert(opts->dir_map, cache_path, cache_path, &error);
- if (error < 0)
- goto done;
- }
- }
-
- error = 0;
-
- /* check that full path really is a directory if requested & needed */
- if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
- lastch != '\0') {
- opts->perfdata.stat_calls++;
-
- if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
- git_error_set(GIT_ERROR_OS, "path is not a directory '%s'",
- make_path.ptr);
- error = GIT_ENOTFOUND;
- }
- }
-
-done:
- git_buf_dispose(&make_path);
- return error;
-}
-
-typedef struct {
- const char *base;
- size_t baselen;
- uint32_t flags;
- int depth;
-} futils__rmdir_data;
-
-#define FUTILS_MAX_DEPTH 100
-
-static int futils__error_cannot_rmdir(const char *path, const char *filemsg)
-{
- if (filemsg)
- git_error_set(GIT_ERROR_OS, "could not remove directory '%s': %s",
- path, filemsg);
- else
- git_error_set(GIT_ERROR_OS, "could not remove directory '%s'", path);
-
- return -1;
-}
-
-static int futils__rm_first_parent(git_buf *path, const char *ceiling)
-{
- int error = GIT_ENOTFOUND;
- struct stat st;
-
- while (error == GIT_ENOTFOUND) {
- git_buf_rtruncate_at_char(path, '/');
-
- if (!path->size || git__prefixcmp(path->ptr, ceiling) != 0)
- error = 0;
- else if (p_lstat_posixly(path->ptr, &st) == 0) {
- if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
- error = p_unlink(path->ptr);
- else if (!S_ISDIR(st.st_mode))
- error = -1; /* fail to remove non-regular file */
- } else if (errno != ENOTDIR)
- error = -1;
- }
-
- if (error)
- futils__error_cannot_rmdir(path->ptr, "cannot remove parent");
-
- return error;
-}
-
-static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
-{
- int error = 0;
- futils__rmdir_data *data = opaque;
- struct stat st;
-
- if (data->depth > FUTILS_MAX_DEPTH)
- error = futils__error_cannot_rmdir(
- path->ptr, "directory nesting too deep");
-
- else if ((error = p_lstat_posixly(path->ptr, &st)) < 0) {
- if (errno == ENOENT)
- error = 0;
- else if (errno == ENOTDIR) {
- /* asked to remove a/b/c/d/e and a/b is a normal file */
- if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0)
- error = futils__rm_first_parent(path, data->base);
- else
- futils__error_cannot_rmdir(
- path->ptr, "parent is not directory");
- }
- else
- error = git_path_set_error(errno, path->ptr, "rmdir");
- }
-
- else if (S_ISDIR(st.st_mode)) {
- data->depth++;
-
- error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data);
-
- data->depth--;
-
- if (error < 0)
- return error;
-
- if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0)
- return error;
-
- if ((error = p_rmdir(path->ptr)) < 0) {
- if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
- (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY))
- error = 0;
- else
- error = git_path_set_error(errno, path->ptr, "rmdir");
- }
- }
-
- else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) {
- if (p_unlink(path->ptr) < 0)
- error = git_path_set_error(errno, path->ptr, "remove");
- }
-
- else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0)
- error = futils__error_cannot_rmdir(path->ptr, "still present");
-
- return error;
-}
-
-static int futils__rmdir_empty_parent(void *opaque, const char *path)
-{
- futils__rmdir_data *data = opaque;
- int error = 0;
-
- if (strlen(path) <= data->baselen)
- error = GIT_ITEROVER;
-
- else if (p_rmdir(path) < 0) {
- int en = errno;
-
- if (en == ENOENT || en == ENOTDIR) {
- /* do nothing */
- } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 &&
- en == EBUSY) {
- error = git_path_set_error(errno, path, "rmdir");
- } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
- error = GIT_ITEROVER;
- } else {
- error = git_path_set_error(errno, path, "rmdir");
- }
- }
-
- return error;
-}
-
-int git_futils_rmdir_r(
- const char *path, const char *base, uint32_t flags)
-{
- int error;
- git_buf fullpath = GIT_BUF_INIT;
- futils__rmdir_data data;
-
- /* build path and find "root" where we should start calling mkdir */
- if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0)
- return -1;
-
- memset(&data, 0, sizeof(data));
- data.base = base ? base : "";
- data.baselen = base ? strlen(base) : 0;
- data.flags = flags;
-
- error = futils__rmdir_recurs_foreach(&data, &fullpath);
-
- /* remove now-empty parents if requested */
- if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0)
- error = git_path_walk_up(
- &fullpath, base, futils__rmdir_empty_parent, &data);
-
- if (error == GIT_ITEROVER) {
- git_error_clear();
- error = 0;
- }
-
- git_buf_dispose(&fullpath);
-
- return error;
-}
-
-int git_futils_fake_symlink(const char *old, const char *new)
-{
- int retcode = GIT_ERROR;
- int fd = git_futils_creat_withpath(new, 0755, 0644);
- if (fd >= 0) {
- retcode = p_write(fd, old, strlen(old));
- p_close(fd);
- }
- return retcode;
-}
-
-static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done)
-{
- int error = 0;
- char buffer[FILEIO_BUFSIZE];
- ssize_t len = 0;
-
- while (!error && (len = p_read(ifd, buffer, sizeof(buffer))) > 0)
- /* p_write() does not have the same semantics as write(). It loops
- * internally and will return 0 when it has completed writing.
- */
- error = p_write(ofd, buffer, len);
-
- if (len < 0) {
- git_error_set(GIT_ERROR_OS, "read error while copying file");
- error = (int)len;
- }
-
- if (error < 0)
- git_error_set(GIT_ERROR_OS, "write error while copying file");
-
- if (close_fd_when_done) {
- p_close(ifd);
- p_close(ofd);
- }
-
- return error;
-}
-
-int git_futils_cp(const char *from, const char *to, mode_t filemode)
-{
- int ifd, ofd;
-
- if ((ifd = git_futils_open_ro(from)) < 0)
- return ifd;
-
- if ((ofd = p_open(to, O_WRONLY | O_CREAT | O_EXCL, filemode)) < 0) {
- p_close(ifd);
- return git_path_set_error(errno, to, "open for writing");
- }
-
- return cp_by_fd(ifd, ofd, true);
-}
-
-int git_futils_touch(const char *path, time_t *when)
-{
- struct p_timeval times[2];
- int ret;
-
- times[0].tv_sec = times[1].tv_sec = when ? *when : time(NULL);
- times[0].tv_usec = times[1].tv_usec = 0;
-
- ret = p_utimes(path, times);
-
- return (ret < 0) ? git_path_set_error(errno, path, "touch") : 0;
-}
-
-static int cp_link(const char *from, const char *to, size_t link_size)
-{
- int error = 0;
- ssize_t read_len;
- char *link_data;
- size_t alloc_size;
-
- GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, link_size, 1);
- link_data = git__malloc(alloc_size);
- GIT_ERROR_CHECK_ALLOC(link_data);
-
- read_len = p_readlink(from, link_data, link_size);
- if (read_len != (ssize_t)link_size) {
- git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", from);
- error = -1;
- }
- else {
- link_data[read_len] = '\0';
-
- if (p_symlink(link_data, to) < 0) {
- git_error_set(GIT_ERROR_OS, "could not symlink '%s' as '%s'",
- link_data, to);
- error = -1;
- }
- }
-
- git__free(link_data);
- return error;
-}
-
-typedef struct {
- const char *to_root;
- git_buf to;
- ssize_t from_prefix;
- uint32_t flags;
- uint32_t mkdir_flags;
- mode_t dirmode;
-} cp_r_info;
-
-#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10)
-
-static int _cp_r_mkdir(cp_r_info *info, git_buf *from)
-{
- int error = 0;
-
- /* create root directory the first time we need to create a directory */
- if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) {
- error = git_futils_mkdir(
- info->to_root, info->dirmode,
- (info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0);
-
- info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT;
- }
-
- /* create directory with root as base to prevent excess chmods */
- if (!error)
- error = git_futils_mkdir_relative(
- from->ptr + info->from_prefix, info->to_root,
- info->dirmode, info->mkdir_flags, NULL);
-
- return error;
-}
-
-static int _cp_r_callback(void *ref, git_buf *from)
-{
- int error = 0;
- cp_r_info *info = ref;
- struct stat from_st, to_st;
- bool exists = false;
-
- if ((info->flags & GIT_CPDIR_COPY_DOTFILES) == 0 &&
- from->ptr[git_path_basename_offset(from)] == '.')
- return 0;
-
- if ((error = git_buf_joinpath(
- &info->to, info->to_root, from->ptr + info->from_prefix)) < 0)
- return error;
-
- if (!(error = git_path_lstat(info->to.ptr, &to_st)))
- exists = true;
- else if (error != GIT_ENOTFOUND)
- return error;
- else {
- git_error_clear();
- error = 0;
- }
-
- if ((error = git_path_lstat(from->ptr, &from_st)) < 0)
- return error;
-
- if (S_ISDIR(from_st.st_mode)) {
- mode_t oldmode = info->dirmode;
-
- /* if we are not chmod'ing, then overwrite dirmode */
- if ((info->flags & GIT_CPDIR_CHMOD_DIRS) == 0)
- info->dirmode = from_st.st_mode;
-
- /* make directory now if CREATE_EMPTY_DIRS is requested and needed */
- if (!exists && (info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) != 0)
- error = _cp_r_mkdir(info, from);
-
- /* recurse onto target directory */
- if (!error && (!exists || S_ISDIR(to_st.st_mode)))
- error = git_path_direach(from, 0, _cp_r_callback, info);
-
- if (oldmode != 0)
- info->dirmode = oldmode;
-
- return error;
- }
-
- if (exists) {
- if ((info->flags & GIT_CPDIR_OVERWRITE) == 0)
- return 0;
-
- if (p_unlink(info->to.ptr) < 0) {
- git_error_set(GIT_ERROR_OS, "cannot overwrite existing file '%s'",
- info->to.ptr);
- return GIT_EEXISTS;
- }
- }
-
- /* Done if this isn't a regular file or a symlink */
- if (!S_ISREG(from_st.st_mode) &&
- (!S_ISLNK(from_st.st_mode) ||
- (info->flags & GIT_CPDIR_COPY_SYMLINKS) == 0))
- return 0;
-
- /* Make container directory on demand if needed */
- if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 &&
- (error = _cp_r_mkdir(info, from)) < 0)
- return error;
-
- /* make symlink or regular file */
- if (info->flags & GIT_CPDIR_LINK_FILES) {
- if ((error = p_link(from->ptr, info->to.ptr)) < 0)
- git_error_set(GIT_ERROR_OS, "failed to link '%s'", from->ptr);
- } else if (S_ISLNK(from_st.st_mode)) {
- error = cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size);
- } else {
- mode_t usemode = from_st.st_mode;
-
- if ((info->flags & GIT_CPDIR_SIMPLE_TO_MODE) != 0)
- usemode = GIT_PERMS_FOR_WRITE(usemode);
-
- error = git_futils_cp(from->ptr, info->to.ptr, usemode);
- }
-
- return error;
-}
-
-int git_futils_cp_r(
- const char *from,
- const char *to,
- uint32_t flags,
- mode_t dirmode)
-{
- int error;
- git_buf path = GIT_BUF_INIT;
- cp_r_info info;
-
- if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */
- return -1;
-
- memset(&info, 0, sizeof(info));
- info.to_root = to;
- info.flags = flags;
- info.dirmode = dirmode;
- info.from_prefix = path.size;
- git_buf_init(&info.to, 0);
-
- /* precalculate mkdir flags */
- if ((flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0) {
- /* if not creating empty dirs, then use mkdir to create the path on
- * demand right before files are copied.
- */
- info.mkdir_flags = GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST;
- if ((flags & GIT_CPDIR_CHMOD_DIRS) != 0)
- info.mkdir_flags |= GIT_MKDIR_CHMOD_PATH;
- } else {
- /* otherwise, we will do simple mkdir as directories are encountered */
- info.mkdir_flags =
- ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) ? GIT_MKDIR_CHMOD : 0;
- }
-
- error = _cp_r_callback(&info, &path);
-
- git_buf_dispose(&path);
- git_buf_dispose(&info.to);
-
- return error;
-}
-
-int git_futils_filestamp_check(
- git_futils_filestamp *stamp, const char *path)
-{
- struct stat st;
-
- /* if the stamp is NULL, then always reload */
- if (stamp == NULL)
- return 1;
-
- if (p_stat(path, &st) < 0)
- return GIT_ENOTFOUND;
-
- if (stamp->mtime.tv_sec == st.st_mtime &&
-#if defined(GIT_USE_NSEC)
- stamp->mtime.tv_nsec == st.st_mtime_nsec &&
-#endif
- stamp->size == (git_off_t)st.st_size &&
- stamp->ino == (unsigned int)st.st_ino)
- return 0;
-
- stamp->mtime.tv_sec = st.st_mtime;
-#if defined(GIT_USE_NSEC)
- stamp->mtime.tv_nsec = st.st_mtime_nsec;
-#endif
- stamp->size = (git_off_t)st.st_size;
- stamp->ino = (unsigned int)st.st_ino;
-
- return 1;
-}
-
-void git_futils_filestamp_set(
- git_futils_filestamp *target, const git_futils_filestamp *source)
-{
- assert(target);
-
- if (source)
- memcpy(target, source, sizeof(*target));
- else
- memset(target, 0, sizeof(*target));
-}
-
-
-void git_futils_filestamp_set_from_stat(
- git_futils_filestamp *stamp, struct stat *st)
-{
- if (st) {
- stamp->mtime.tv_sec = st->st_mtime;
-#if defined(GIT_USE_NSEC)
- stamp->mtime.tv_nsec = st->st_mtime_nsec;
-#else
- stamp->mtime.tv_nsec = 0;
-#endif
- stamp->size = (git_off_t)st->st_size;
- stamp->ino = (unsigned int)st->st_ino;
- } else {
- memset(stamp, 0, sizeof(*stamp));
- }
-}
-
-int git_futils_fsync_dir(const char *path)
-{
-#ifdef GIT_WIN32
- GIT_UNUSED(path);
- return 0;
-#else
- int fd, error = -1;
-
- if ((fd = p_open(path, O_RDONLY)) < 0) {
- git_error_set(GIT_ERROR_OS, "failed to open directory '%s' for fsync", path);
- return -1;
- }
-
- if ((error = p_fsync(fd)) < 0)
- git_error_set(GIT_ERROR_OS, "failed to fsync directory '%s'", path);
-
- p_close(fd);
- return error;
-#endif
-}
-
-int git_futils_fsync_parent(const char *path)
-{
- char *parent;
- int error;
-
- if ((parent = git_path_dirname(path)) == NULL)
- return -1;
-
- error = git_futils_fsync_dir(parent);
- git__free(parent);
- return error;
-}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_fileops_h__
-#define INCLUDE_fileops_h__
-
-#include "common.h"
-
-#include "map.h"
-#include "posix.h"
-#include "path.h"
-#include "pool.h"
-#include "strmap.h"
-#include "oid.h"
-
-/**
- * Filebuffer methods
- *
- * Read whole files into an in-memory buffer for processing
- */
-extern int git_futils_readbuffer(git_buf *obj, const char *path);
-extern int git_futils_readbuffer_updated(
- git_buf *obj, const char *path, git_oid *checksum, int *updated);
-extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len);
-
-/* Additional constants for `git_futils_writebuffer`'s `open_flags`. We
- * support these internally and they will be removed before the `open` call.
- */
-#ifndef O_FSYNC
-# define O_FSYNC (1 << 31)
-#endif
-
-extern int git_futils_writebuffer(
- const git_buf *buf, const char *path, int open_flags, mode_t mode);
-
-/**
- * File utils
- *
- * These are custom filesystem-related helper methods. They are
- * rather high level, and wrap the underlying POSIX methods
- *
- * All these methods return 0 on success,
- * or an error code on failure and an error message is set.
- */
-
-/**
- * Create and open a file, while also
- * creating all the folders in its path
- */
-extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode);
-
-/**
- * Create and open a process-locked file
- */
-extern int git_futils_creat_locked(const char *path, const mode_t mode);
-
-/**
- * Create and open a process-locked file, while
- * also creating all the folders in its path
- */
-extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode);
-
-/**
- * Create a path recursively.
- */
-extern int git_futils_mkdir_r(const char *path, const mode_t mode);
-
-/**
- * Flags to pass to `git_futils_mkdir`.
- *
- * * GIT_MKDIR_EXCL is "exclusive" - i.e. generate an error if dir exists.
- * * GIT_MKDIR_PATH says to make all components in the path.
- * * GIT_MKDIR_CHMOD says to chmod the final directory entry after creation
- * * GIT_MKDIR_CHMOD_PATH says to chmod each directory component in the path
- * * GIT_MKDIR_SKIP_LAST says to leave off the last element of the path
- * * GIT_MKDIR_SKIP_LAST2 says to leave off the last 2 elements of the path
- * * GIT_MKDIR_VERIFY_DIR says confirm final item is a dir, not just EEXIST
- * * GIT_MKDIR_REMOVE_FILES says to remove files and recreate dirs
- * * GIT_MKDIR_REMOVE_SYMLINKS says to remove symlinks and recreate dirs
- *
- * Note that the chmod options will be executed even if the directory already
- * exists, unless GIT_MKDIR_EXCL is given.
- */
-typedef enum {
- GIT_MKDIR_EXCL = 1,
- GIT_MKDIR_PATH = 2,
- GIT_MKDIR_CHMOD = 4,
- GIT_MKDIR_CHMOD_PATH = 8,
- GIT_MKDIR_SKIP_LAST = 16,
- GIT_MKDIR_SKIP_LAST2 = 32,
- GIT_MKDIR_VERIFY_DIR = 64,
- GIT_MKDIR_REMOVE_FILES = 128,
- GIT_MKDIR_REMOVE_SYMLINKS = 256,
-} git_futils_mkdir_flags;
-
-struct git_futils_mkdir_perfdata
-{
- size_t stat_calls;
- size_t mkdir_calls;
- size_t chmod_calls;
-};
-
-struct git_futils_mkdir_options
-{
- git_strmap *dir_map;
- git_pool *pool;
- struct git_futils_mkdir_perfdata perfdata;
-};
-
-/**
- * Create a directory or entire path.
- *
- * This makes a directory (and the entire path leading up to it if requested),
- * and optionally chmods the directory immediately after (or each part of the
- * path if requested).
- *
- * @param path The path to create, relative to base.
- * @param base Root for relative path. These directories will never be made.
- * @param mode The mode to use for created directories.
- * @param flags Combination of the mkdir flags above.
- * @param opts Extended options, or null.
- * @return 0 on success, else error code
- */
-extern int git_futils_mkdir_relative(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
-
-/**
- * Create a directory or entire path. Similar to `git_futils_mkdir_relative`
- * without performance data.
- */
-extern int git_futils_mkdir(const char *path, mode_t mode, uint32_t flags);
-
-/**
- * Create all the folders required to contain
- * the full path of a file
- */
-extern int git_futils_mkpath2file(const char *path, const mode_t mode);
-
-/**
- * Flags to pass to `git_futils_rmdir_r`.
- *
- * * GIT_RMDIR_EMPTY_HIERARCHY - the default; remove hierarchy of empty
- * dirs and generate error if any files are found.
- * * GIT_RMDIR_REMOVE_FILES - attempt to remove files in the hierarchy.
- * * GIT_RMDIR_SKIP_NONEMPTY - skip non-empty directories with no error.
- * * GIT_RMDIR_EMPTY_PARENTS - remove containing directories up to base
- * if removing this item leaves them empty
- * * GIT_RMDIR_REMOVE_BLOCKERS - remove blocking file that causes ENOTDIR
- * * GIT_RMDIR_SKIP_ROOT - don't remove root directory itself
- */
-typedef enum {
- GIT_RMDIR_EMPTY_HIERARCHY = 0,
- GIT_RMDIR_REMOVE_FILES = (1 << 0),
- GIT_RMDIR_SKIP_NONEMPTY = (1 << 1),
- GIT_RMDIR_EMPTY_PARENTS = (1 << 2),
- GIT_RMDIR_REMOVE_BLOCKERS = (1 << 3),
- GIT_RMDIR_SKIP_ROOT = (1 << 4),
-} git_futils_rmdir_flags;
-
-/**
- * Remove path and any files and directories beneath it.
- *
- * @param path Path to the top level directory to process.
- * @param base Root for relative path.
- * @param flags Combination of git_futils_rmdir_flags values
- * @return 0 on success; -1 on error.
- */
-extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags);
-
-/**
- * Create and open a temporary file with a `_git2_` suffix.
- * Writes the filename into path_out.
- * @return On success, an open file descriptor, else an error code < 0.
- */
-extern int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode);
-
-/**
- * Move a file on the filesystem, create the
- * destination path if it doesn't exist
- */
-extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode);
-
-/**
- * Copy a file
- *
- * The filemode will be used for the newly created file.
- */
-extern int git_futils_cp(
- const char *from,
- const char *to,
- mode_t filemode);
-
-/**
- * Set the files atime and mtime to the given time, or the current time
- * if `ts` is NULL.
- */
-extern int git_futils_touch(const char *path, time_t *when);
-
-/**
- * Flags that can be passed to `git_futils_cp_r`.
- *
- * - GIT_CPDIR_CREATE_EMPTY_DIRS: create directories even if there are no
- * files under them (otherwise directories will only be created lazily
- * when a file inside them is copied).
- * - GIT_CPDIR_COPY_SYMLINKS: copy symlinks, otherwise they are ignored.
- * - GIT_CPDIR_COPY_DOTFILES: copy files with leading '.', otherwise ignored.
- * - GIT_CPDIR_OVERWRITE: overwrite pre-existing files with source content,
- * otherwise they are silently skipped.
- * - GIT_CPDIR_CHMOD_DIRS: explicitly chmod directories to `dirmode`
- * - GIT_CPDIR_SIMPLE_TO_MODE: default tries to replicate the mode of the
- * source file to the target; with this flag, always use 0666 (or 0777 if
- * source has exec bits set) for target.
- * - GIT_CPDIR_LINK_FILES will try to use hardlinks for the files
- */
-typedef enum {
- GIT_CPDIR_CREATE_EMPTY_DIRS = (1u << 0),
- GIT_CPDIR_COPY_SYMLINKS = (1u << 1),
- GIT_CPDIR_COPY_DOTFILES = (1u << 2),
- GIT_CPDIR_OVERWRITE = (1u << 3),
- GIT_CPDIR_CHMOD_DIRS = (1u << 4),
- GIT_CPDIR_SIMPLE_TO_MODE = (1u << 5),
- GIT_CPDIR_LINK_FILES = (1u << 6),
-} git_futils_cpdir_flags;
-
-/**
- * Copy a directory tree.
- *
- * This copies directories and files from one root to another. You can
- * pass a combinationof GIT_CPDIR flags as defined above.
- *
- * If you pass the CHMOD flag, then the dirmode will be applied to all
- * directories that are created during the copy, overiding the natural
- * permissions. If you do not pass the CHMOD flag, then the dirmode
- * will actually be copied from the source files and the `dirmode` arg
- * will be ignored.
- */
-extern int git_futils_cp_r(
- const char *from,
- const char *to,
- uint32_t flags,
- mode_t dirmode);
-
-/**
- * Open a file readonly and set error if needed.
- */
-extern int git_futils_open_ro(const char *path);
-
-/**
- * Truncate a file, creating it if it doesn't exist.
- */
-extern int git_futils_truncate(const char *path, int mode);
-
-/**
- * Get the filesize in bytes of a file
- */
-extern git_off_t git_futils_filesize(git_file fd);
-
-#define GIT_PERMS_IS_EXEC(MODE) (((MODE) & 0111) != 0)
-#define GIT_PERMS_CANONICAL(MODE) (GIT_PERMS_IS_EXEC(MODE) ? 0755 : 0644)
-#define GIT_PERMS_FOR_WRITE(MODE) (GIT_PERMS_IS_EXEC(MODE) ? 0777 : 0666)
-
-#define GIT_MODE_PERMS_MASK 0777
-#define GIT_MODE_TYPE_MASK 0170000
-#define GIT_MODE_TYPE(MODE) ((MODE) & GIT_MODE_TYPE_MASK)
-#define GIT_MODE_ISBLOB(MODE) (GIT_MODE_TYPE(MODE) == GIT_MODE_TYPE(GIT_FILEMODE_BLOB))
-
-/**
- * Convert a mode_t from the OS to a legal git mode_t value.
- */
-extern mode_t git_futils_canonical_mode(mode_t raw_mode);
-
-
-/**
- * Read-only map all or part of a file into memory.
- * When possible this function should favor a virtual memory
- * style mapping over some form of malloc()+read(), as the
- * data access will be random and is not likely to touch the
- * majority of the region requested.
- *
- * @param out buffer to populate with the mapping information.
- * @param fd open descriptor to configure the mapping from.
- * @param begin first byte to map, this should be page aligned.
- * @param len number of bytes to map.
- * @return
- * - 0 on success;
- * - -1 on error.
- */
-extern int git_futils_mmap_ro(
- git_map *out,
- git_file fd,
- git_off_t begin,
- size_t len);
-
-/**
- * Read-only map an entire file.
- *
- * @param out buffer to populate with the mapping information.
- * @param path path to file to be opened.
- * @return
- * - 0 on success;
- * - GIT_ENOTFOUND if not found;
- * - -1 on an unspecified OS related error.
- */
-extern int git_futils_mmap_ro_file(
- git_map *out,
- const char *path);
-
-/**
- * Release the memory associated with a previous memory mapping.
- * @param map the mapping description previously configured.
- */
-extern void git_futils_mmap_free(git_map *map);
-
-/**
- * Create a "fake" symlink (text file containing the target path).
- *
- * @param new symlink file to be created
- * @param old original symlink target
- * @return 0 on success, -1 on error
- */
-extern int git_futils_fake_symlink(const char *new, const char *old);
-
-/**
- * A file stamp represents a snapshot of information about a file that can
- * be used to test if the file changes. This portable implementation is
- * based on stat data about that file, but it is possible that OS specific
- * versions could be implemented in the future.
- */
-typedef struct {
- struct timespec mtime;
- git_off_t size;
- unsigned int ino;
-} git_futils_filestamp;
-
-/**
- * Compare stat information for file with reference info.
- *
- * This function updates the file stamp to current data for the given path
- * and returns 0 if the file is up-to-date relative to the prior setting,
- * 1 if the file has been changed, or GIT_ENOTFOUND if the file doesn't
- * exist. This will not call git_error_set, so you must set the error if you
- * plan to return an error.
- *
- * @param stamp File stamp to be checked
- * @param path Path to stat and check if changed
- * @return 0 if up-to-date, 1 if out-of-date, GIT_ENOTFOUND if cannot stat
- */
-extern int git_futils_filestamp_check(
- git_futils_filestamp *stamp, const char *path);
-
-/**
- * Set or reset file stamp data
- *
- * This writes the target file stamp. If the source is NULL, this will set
- * the target stamp to values that will definitely be out of date. If the
- * source is not NULL, this copies the source values to the target.
- *
- * @param tgt File stamp to write to
- * @param src File stamp to copy from or NULL to clear the target
- */
-extern void git_futils_filestamp_set(
- git_futils_filestamp *tgt, const git_futils_filestamp *src);
-
-/**
- * Set file stamp data from stat structure
- */
-extern void git_futils_filestamp_set_from_stat(
- git_futils_filestamp *stamp, struct stat *st);
-
-/**
- * `fsync` the parent directory of the given path, if `fsync` is
- * supported for directories on this platform.
- *
- * @param path Path of the directory to sync.
- * @return 0 on success, -1 on error
- */
-extern int git_futils_fsync_dir(const char *path);
-
-/**
- * `fsync` the parent directory of the given path, if `fsync` is
- * supported for directories on this platform.
- *
- * @param path Path of the file whose parent directory should be synced.
- * @return 0 on success, -1 on error
- */
-extern int git_futils_fsync_parent(const char *path);
-
-#endif
#include "filter.h"
#include "common.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "repository.h"
#include "global.h"
const git_oid *git_filter_source_id(const git_filter_source *src)
{
- return git_oid_iszero(&src->oid) ? NULL : &src->oid;
+ return git_oid_is_zero(&src->oid) ? NULL : &src->oid;
}
git_filter_mode_t git_filter_source_mode(const git_filter_source *src)
git_filter_def *fdef,
const git_filter_source *src)
{
- int error;
- size_t i;
const char **strs = git__calloc(fdef->nattrs, sizeof(const char *));
+ uint32_t flags = 0;
+ size_t i;
+ int error;
+
GIT_ERROR_CHECK_ALLOC(strs);
+ if ((src->flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
+ flags |= GIT_ATTR_CHECK_NO_SYSTEM;
+
+ if ((src->flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
+ flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
+
error = git_attr_get_many_with_session(
- strs, repo, attr_session, 0, src->path, fdef->nattrs, fdef->attrs);
+ strs, repo, attr_session, flags, src->path, fdef->nattrs, fdef->attrs);
/* if no values were found but no matches are needed, it's okay! */
if (error == GIT_ENOTFOUND && !fdef->nmatches) {
for (i = 0; !error && i < fdef->nattrs; ++i) {
const char *want = fdef->attrs[fdef->nattrs + i];
- git_attr_t want_type, found_type;
+ git_attr_value_t want_type, found_type;
if (!want)
continue;
if (want_type != found_type)
error = GIT_ENOTFOUND;
- else if (want_type == GIT_ATTR_VALUE_T &&
+ else if (want_type == GIT_ATTR_VALUE_STRING &&
strcmp(want, strs[i]) &&
strcmp(want, "*"))
error = GIT_ENOTFOUND;
static int buf_from_blob(git_buf *out, git_blob *blob)
{
- git_off_t rawsize = git_blob_rawsize(blob);
+ git_object_size_t rawsize = git_blob_rawsize(blob);
if (!git__is_sizet(rawsize)) {
git_error_set(GIT_ERROR_OS, "blob is too large to filter");
return error;
}
-void stream_list_free(git_vector *streams)
+static void filter_streams_free(git_vector *streams)
{
git_writestream *stream;
size_t i;
if (fd >= 0)
p_close(fd);
- stream_list_free(&filter_streams);
+ filter_streams_free(&filter_streams);
git_buf_dispose(&abspath);
return error;
}
if (initialized)
error |= stream_start->close(stream_start);
- stream_list_free(&filter_streams);
+ filter_streams_free(&filter_streams);
return error;
}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-/*
- * This file contains code originally derrived from OpenBSD fnmatch.c
- *
- * Copyright (c) 1989, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 THE REGENTS OR CONTRIBUTORS 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.
- */
-
-/*
- * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
- * Compares a filename or pathname to a pattern.
- */
-
-#include "fnmatch.h"
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-
-#define EOS '\0'
-
-#define RANGE_MATCH 1
-#define RANGE_NOMATCH 0
-#define RANGE_ERROR (-1)
-
-static int rangematch(const char *, char, int, char **);
-
-static int
-p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
-{
- const char *stringstart;
- char *newp;
- char c, test;
- int recurs_flags = flags & ~FNM_PERIOD;
-
- if (recurs-- == 0)
- return FNM_NORES;
-
- for (stringstart = string;;)
- switch (c = *pattern++) {
- case EOS:
- if ((flags & FNM_LEADING_DIR) && *string == '/')
- return (0);
- return (*string == EOS ? 0 : FNM_NOMATCH);
- case '?':
- if (*string == EOS)
- return (FNM_NOMATCH);
- if (*string == '/' && (flags & FNM_PATHNAME))
- return (FNM_NOMATCH);
- if (*string == '.' && (flags & FNM_PERIOD) &&
- (string == stringstart ||
- ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
- return (FNM_NOMATCH);
- ++string;
- break;
- case '*':
- c = *pattern;
-
- /* Let '**' override PATHNAME match for this segment.
- * It will be restored if/when we recurse below.
- */
- if (c == '*') {
- c = *++pattern;
- /* star-star-slash is at the end, match by default */
- if (c == EOS)
- return 0;
- /* Double-star must be at end or between slashes */
- if (c != '/')
- return (FNM_NOMATCH);
-
- c = *++pattern;
- do {
- int e = p_fnmatchx(pattern, string, recurs_flags, recurs);
- if (e != FNM_NOMATCH)
- return e;
- string = strchr(string, '/');
- } while (string++);
-
- /* If we get here, we didn't find a match */
- return FNM_NOMATCH;
- }
-
- if (*string == '.' && (flags & FNM_PERIOD) &&
- (string == stringstart ||
- ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
- return (FNM_NOMATCH);
-
- /* Optimize for pattern with * at end or before /. */
- if (c == EOS) {
- if (flags & FNM_PATHNAME)
- return ((flags & FNM_LEADING_DIR) ||
- strchr(string, '/') == NULL ?
- 0 : FNM_NOMATCH);
- else
- return (0);
- } else if (c == '/' && (flags & FNM_PATHNAME)) {
- if ((string = strchr(string, '/')) == NULL)
- return (FNM_NOMATCH);
- break;
- }
-
- /* General case, use recursion. */
- while ((test = *string) != EOS) {
- int e;
-
- e = p_fnmatchx(pattern, string, recurs_flags, recurs);
- if (e != FNM_NOMATCH)
- return e;
- if (test == '/' && (flags & FNM_PATHNAME))
- break;
- ++string;
- }
- return (FNM_NOMATCH);
- case '[':
- if (*string == EOS)
- return (FNM_NOMATCH);
- if (*string == '/' && (flags & FNM_PATHNAME))
- return (FNM_NOMATCH);
- if (*string == '.' && (flags & FNM_PERIOD) &&
- (string == stringstart ||
- ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
- return (FNM_NOMATCH);
-
- switch (rangematch(pattern, *string, flags, &newp)) {
- case RANGE_ERROR:
- /* not a good range, treat as normal text */
- goto normal;
- case RANGE_MATCH:
- pattern = newp;
- break;
- case RANGE_NOMATCH:
- return (FNM_NOMATCH);
- }
- ++string;
- break;
- case '\\':
- if (!(flags & FNM_NOESCAPE)) {
- if ((c = *pattern++) == EOS) {
- c = '\\';
- --pattern;
- }
- }
- /* FALLTHROUGH */
- default:
- normal:
- if (c != *string && !((flags & FNM_CASEFOLD) &&
- (git__tolower((unsigned char)c) ==
- git__tolower((unsigned char)*string))))
- return (FNM_NOMATCH);
- ++string;
- break;
- }
- /* NOTREACHED */
-}
-
-static int
-rangematch(const char *pattern, char test, int flags, char **newp)
-{
- int negate, ok;
- char c, c2;
-
- /*
- * A bracket expression starting with an unquoted circumflex
- * character produces unspecified results (IEEE 1003.2-1992,
- * 3.13.2). This implementation treats it like '!', for
- * consistency with the regular expression syntax.
- * J.T. Conklin (conklin@ngai.kaleida.com)
- */
- if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
- ++pattern;
-
- if (flags & FNM_CASEFOLD)
- test = (char)git__tolower((unsigned char)test);
-
- /*
- * A right bracket shall lose its special meaning and represent
- * itself in a bracket expression if it occurs first in the list.
- * -- POSIX.2 2.8.3.2
- */
- ok = 0;
- c = *pattern++;
- do {
- if (c == '\\' && !(flags & FNM_NOESCAPE))
- c = *pattern++;
- if (c == EOS)
- return (RANGE_ERROR);
- if (c == '/' && (flags & FNM_PATHNAME))
- return (RANGE_NOMATCH);
- if ((flags & FNM_CASEFOLD))
- c = (char)git__tolower((unsigned char)c);
- if (*pattern == '-'
- && (c2 = *(pattern+1)) != EOS && c2 != ']') {
- pattern += 2;
- if (c2 == '\\' && !(flags & FNM_NOESCAPE))
- c2 = *pattern++;
- if (c2 == EOS)
- return (RANGE_ERROR);
- if (flags & FNM_CASEFOLD)
- c2 = (char)git__tolower((unsigned char)c2);
- if (c <= test && test <= c2)
- ok = 1;
- } else if (c == test)
- ok = 1;
- } while ((c = *pattern++) != ']');
-
- *newp = (char *)pattern;
- return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
-}
-
-int
-p_fnmatch(const char *pattern, const char *string, int flags)
-{
- return p_fnmatchx(pattern, string, flags, 64);
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- * 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.
- *
- * 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 THE
- * COPYRIGHT OWNER OR CONTRIBUTORS 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.
- */
-#ifndef INCLUDE_fnmatch_h__
-#define INCLUDE_fnmatch_h__
-
-#include "common.h"
-
-#define FNM_NOMATCH 1 /* Match failed. */
-#define FNM_NOSYS 2 /* Function not supported (unused). */
-#define FNM_NORES 3 /* Out of resources */
-
-#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
-#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
-#define FNM_PERIOD 0x04 /* Period must be matched by period. */
-#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
-#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
-
-#define FNM_IGNORECASE FNM_CASEFOLD
-#define FNM_FILE_NAME FNM_PATHNAME
-
-extern int p_fnmatch(const char *pattern, const char *string, int flags);
-
-#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "futils.h"
+
+#include "global.h"
+#include "strmap.h"
+#include <ctype.h>
+#if GIT_WIN32
+#include "win32/findfile.h"
+#endif
+
+int git_futils_mkpath2file(const char *file_path, const mode_t mode)
+{
+ return git_futils_mkdir(
+ file_path, mode,
+ GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
+}
+
+int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode)
+{
+ int fd;
+ mode_t mask;
+
+ p_umask(mask = p_umask(0));
+
+ git_buf_sets(path_out, filename);
+ git_buf_puts(path_out, "_git2_XXXXXX");
+
+ if (git_buf_oom(path_out))
+ return -1;
+
+ if ((fd = p_mkstemp(path_out->ptr)) < 0) {
+ git_error_set(GIT_ERROR_OS,
+ "failed to create temporary file '%s'", path_out->ptr);
+ return -1;
+ }
+
+ if (p_chmod(path_out->ptr, (mode & ~mask))) {
+ git_error_set(GIT_ERROR_OS,
+ "failed to set permissions on file '%s'", path_out->ptr);
+ return -1;
+ }
+
+ return fd;
+}
+
+int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode)
+{
+ int fd;
+
+ if (git_futils_mkpath2file(path, dirmode) < 0)
+ return -1;
+
+ fd = p_creat(path, mode);
+ if (fd < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to create file '%s'", path);
+ return -1;
+ }
+
+ return fd;
+}
+
+int git_futils_creat_locked(const char *path, const mode_t mode)
+{
+ int fd = p_open(path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC,
+ mode);
+
+ if (fd < 0) {
+ int error = errno;
+ git_error_set(GIT_ERROR_OS, "failed to create locked file '%s'", path);
+ switch (error) {
+ case EEXIST:
+ return GIT_ELOCKED;
+ case ENOENT:
+ return GIT_ENOTFOUND;
+ default:
+ return -1;
+ }
+ }
+
+ return fd;
+}
+
+int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode)
+{
+ if (git_futils_mkpath2file(path, dirmode) < 0)
+ return -1;
+
+ return git_futils_creat_locked(path, mode);
+}
+
+int git_futils_open_ro(const char *path)
+{
+ int fd = p_open(path, O_RDONLY);
+ if (fd < 0)
+ return git_path_set_error(errno, path, "open");
+ return fd;
+}
+
+int git_futils_truncate(const char *path, int mode)
+{
+ int fd = p_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
+ if (fd < 0)
+ return git_path_set_error(errno, path, "open");
+
+ close(fd);
+ return 0;
+}
+
+int git_futils_filesize(uint64_t *out, git_file fd)
+{
+ struct stat sb;
+
+ if (p_fstat(fd, &sb)) {
+ git_error_set(GIT_ERROR_OS, "failed to stat file descriptor");
+ return -1;
+ }
+
+ if (sb.st_size < 0) {
+ git_error_set(GIT_ERROR_INVALID, "invalid file size");
+ return -1;
+ }
+
+ *out = sb.st_size;
+ return 0;
+}
+
+mode_t git_futils_canonical_mode(mode_t raw_mode)
+{
+ if (S_ISREG(raw_mode))
+ return S_IFREG | GIT_PERMS_CANONICAL(raw_mode);
+ else if (S_ISLNK(raw_mode))
+ return S_IFLNK;
+ else if (S_ISGITLINK(raw_mode))
+ return S_IFGITLINK;
+ else if (S_ISDIR(raw_mode))
+ return S_IFDIR;
+ else
+ return 0;
+}
+
+int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
+{
+ ssize_t read_size = 0;
+ size_t alloc_len;
+
+ git_buf_clear(buf);
+
+ if (!git__is_ssizet(len)) {
+ git_error_set(GIT_ERROR_INVALID, "read too large");
+ return -1;
+ }
+
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
+ if (git_buf_grow(buf, alloc_len) < 0)
+ return -1;
+
+ /* p_read loops internally to read len bytes */
+ read_size = p_read(fd, buf->ptr, len);
+
+ if (read_size != (ssize_t)len) {
+ git_error_set(GIT_ERROR_OS, "failed to read descriptor");
+ git_buf_dispose(buf);
+ return -1;
+ }
+
+ buf->ptr[read_size] = '\0';
+ buf->size = read_size;
+
+ return 0;
+}
+
+int git_futils_readbuffer_updated(
+ git_buf *out, const char *path, git_oid *checksum, int *updated)
+{
+ int error;
+ git_file fd;
+ struct stat st;
+ git_buf buf = GIT_BUF_INIT;
+ git_oid checksum_new;
+
+ assert(out && path && *path);
+
+ if (updated != NULL)
+ *updated = 0;
+
+ if (p_stat(path, &st) < 0)
+ return git_path_set_error(errno, path, "stat");
+
+
+ if (S_ISDIR(st.st_mode)) {
+ git_error_set(GIT_ERROR_INVALID, "requested file is a directory");
+ return GIT_ENOTFOUND;
+ }
+
+ if (!git__is_sizet(st.st_size+1)) {
+ git_error_set(GIT_ERROR_OS, "invalid regular file stat for '%s'", path);
+ return -1;
+ }
+
+ if ((fd = git_futils_open_ro(path)) < 0)
+ return fd;
+
+ if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) {
+ p_close(fd);
+ return -1;
+ }
+
+ p_close(fd);
+
+ if (checksum) {
+ if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) {
+ git_buf_dispose(&buf);
+ return error;
+ }
+
+ /*
+ * If we were given a checksum, we only want to use it if it's different
+ */
+ if (!git_oid__cmp(checksum, &checksum_new)) {
+ git_buf_dispose(&buf);
+ if (updated)
+ *updated = 0;
+
+ return 0;
+ }
+
+ git_oid_cpy(checksum, &checksum_new);
+ }
+
+ /*
+ * If we're here, the file did change, or the user didn't have an old version
+ */
+ if (updated != NULL)
+ *updated = 1;
+
+ git_buf_swap(out, &buf);
+ git_buf_dispose(&buf);
+
+ return 0;
+}
+
+int git_futils_readbuffer(git_buf *buf, const char *path)
+{
+ return git_futils_readbuffer_updated(buf, path, NULL, NULL);
+}
+
+int git_futils_writebuffer(
+ const git_buf *buf, const char *path, int flags, mode_t mode)
+{
+ int fd, do_fsync = 0, error = 0;
+
+ if (!flags)
+ flags = O_CREAT | O_TRUNC | O_WRONLY;
+
+ if ((flags & O_FSYNC) != 0)
+ do_fsync = 1;
+
+ flags &= ~O_FSYNC;
+
+ if (!mode)
+ mode = GIT_FILEMODE_BLOB;
+
+ if ((fd = p_open(path, flags, mode)) < 0) {
+ git_error_set(GIT_ERROR_OS, "could not open '%s' for writing", path);
+ return fd;
+ }
+
+ if ((error = p_write(fd, git_buf_cstr(buf), git_buf_len(buf))) < 0) {
+ git_error_set(GIT_ERROR_OS, "could not write to '%s'", path);
+ (void)p_close(fd);
+ return error;
+ }
+
+ if (do_fsync && (error = p_fsync(fd)) < 0) {
+ git_error_set(GIT_ERROR_OS, "could not fsync '%s'", path);
+ p_close(fd);
+ return error;
+ }
+
+ if ((error = p_close(fd)) < 0) {
+ git_error_set(GIT_ERROR_OS, "error while closing '%s'", path);
+ return error;
+ }
+
+ if (do_fsync && (flags & O_CREAT))
+ error = git_futils_fsync_parent(path);
+
+ return error;
+}
+
+int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
+{
+ if (git_futils_mkpath2file(to, dirmode) < 0)
+ return -1;
+
+ if (p_rename(from, to) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to rename '%s' to '%s'", from, to);
+ return -1;
+ }
+
+ return 0;
+}
+
+int git_futils_mmap_ro(git_map *out, git_file fd, off64_t begin, size_t len)
+{
+ return p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin);
+}
+
+int git_futils_mmap_ro_file(git_map *out, const char *path)
+{
+ git_file fd = git_futils_open_ro(path);
+ uint64_t len;
+ int result;
+
+ if (fd < 0)
+ return fd;
+
+ if ((result = git_futils_filesize(&len, fd)) < 0)
+ goto out;
+
+ if (!git__is_sizet(len)) {
+ git_error_set(GIT_ERROR_OS, "file `%s` too large to mmap", path);
+ result = -1;
+ goto out;
+ }
+
+ result = git_futils_mmap_ro(out, fd, 0, (size_t)len);
+out:
+ p_close(fd);
+ return result;
+}
+
+void git_futils_mmap_free(git_map *out)
+{
+ p_munmap(out);
+}
+
+GIT_INLINE(int) mkdir_validate_dir(
+ const char *path,
+ struct stat *st,
+ mode_t mode,
+ uint32_t flags,
+ struct git_futils_mkdir_options *opts)
+{
+ /* with exclusive create, existing dir is an error */
+ if ((flags & GIT_MKDIR_EXCL) != 0) {
+ git_error_set(GIT_ERROR_FILESYSTEM,
+ "failed to make directory '%s': directory exists", path);
+ return GIT_EEXISTS;
+ }
+
+ if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) ||
+ (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) {
+ if (p_unlink(path) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to remove %s '%s'",
+ S_ISLNK(st->st_mode) ? "symlink" : "file", path);
+ return GIT_EEXISTS;
+ }
+
+ opts->perfdata.mkdir_calls++;
+
+ if (p_mkdir(path, mode) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path);
+ return GIT_EEXISTS;
+ }
+ }
+
+ else if (S_ISLNK(st->st_mode)) {
+ /* Re-stat the target, make sure it's a directory */
+ opts->perfdata.stat_calls++;
+
+ if (p_stat(path, st) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", path);
+ return GIT_EEXISTS;
+ }
+ }
+
+ else if (!S_ISDIR(st->st_mode)) {
+ git_error_set(GIT_ERROR_FILESYSTEM,
+ "failed to make directory '%s': directory exists", path);
+ return GIT_EEXISTS;
+ }
+
+ return 0;
+}
+
+GIT_INLINE(int) mkdir_validate_mode(
+ const char *path,
+ struct stat *st,
+ bool terminal_path,
+ mode_t mode,
+ uint32_t flags,
+ struct git_futils_mkdir_options *opts)
+{
+ if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) ||
+ (flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) {
+
+ opts->perfdata.chmod_calls++;
+
+ if (p_chmod(path, mode) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to set permissions on '%s'", path);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+GIT_INLINE(int) mkdir_canonicalize(
+ git_buf *path,
+ uint32_t flags)
+{
+ ssize_t root_len;
+
+ if (path->size == 0) {
+ git_error_set(GIT_ERROR_OS, "attempt to create empty path");
+ return -1;
+ }
+
+ /* Trim trailing slashes (except the root) */
+ if ((root_len = git_path_root(path->ptr)) < 0)
+ root_len = 0;
+ else
+ root_len++;
+
+ while (path->size > (size_t)root_len && path->ptr[path->size - 1] == '/')
+ path->ptr[--path->size] = '\0';
+
+ /* if we are not supposed to made the last element, truncate it */
+ if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
+ git_path_dirname_r(path, path->ptr);
+ flags |= GIT_MKDIR_SKIP_LAST;
+ }
+ if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
+ git_path_dirname_r(path, path->ptr);
+ }
+
+ /* We were either given the root path (or trimmed it to
+ * the root), we don't have anything to do.
+ */
+ if (path->size <= (size_t)root_len)
+ git_buf_clear(path);
+
+ return 0;
+}
+
+int git_futils_mkdir(
+ const char *path,
+ mode_t mode,
+ uint32_t flags)
+{
+ git_buf make_path = GIT_BUF_INIT, parent_path = GIT_BUF_INIT;
+ const char *relative;
+ struct git_futils_mkdir_options opts = { 0 };
+ struct stat st;
+ size_t depth = 0;
+ int len = 0, root_len, error;
+
+ if ((error = git_buf_puts(&make_path, path)) < 0 ||
+ (error = mkdir_canonicalize(&make_path, flags)) < 0 ||
+ (error = git_buf_puts(&parent_path, make_path.ptr)) < 0 ||
+ make_path.size == 0)
+ goto done;
+
+ root_len = git_path_root(make_path.ptr);
+
+ /* find the first parent directory that exists. this will be used
+ * as the base to dirname_relative.
+ */
+ for (relative = make_path.ptr; parent_path.size; ) {
+ error = p_lstat(parent_path.ptr, &st);
+
+ if (error == 0) {
+ break;
+ } else if (errno != ENOENT) {
+ git_error_set(GIT_ERROR_OS, "failed to stat '%s'", parent_path.ptr);
+ error = -1;
+ goto done;
+ }
+
+ depth++;
+
+ /* examine the parent of the current path */
+ if ((len = git_path_dirname_r(&parent_path, parent_path.ptr)) < 0) {
+ error = len;
+ goto done;
+ }
+
+ assert(len);
+
+ /*
+ * We've walked all the given path's parents and it's either relative
+ * (the parent is simply '.') or rooted (the length is less than or
+ * equal to length of the root path). The path may be less than the
+ * root path length on Windows, where `C:` == `C:/`.
+ */
+ if ((len == 1 && parent_path.ptr[0] == '.') ||
+ (len == 1 && parent_path.ptr[0] == '/') ||
+ len <= root_len) {
+ relative = make_path.ptr;
+ break;
+ }
+
+ relative = make_path.ptr + len + 1;
+
+ /* not recursive? just make this directory relative to its parent. */
+ if ((flags & GIT_MKDIR_PATH) == 0)
+ break;
+ }
+
+ /* we found an item at the location we're trying to create,
+ * validate it.
+ */
+ if (depth == 0) {
+ error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts);
+
+ if (!error)
+ error = mkdir_validate_mode(
+ make_path.ptr, &st, true, mode, flags, &opts);
+
+ goto done;
+ }
+
+ /* we already took `SKIP_LAST` and `SKIP_LAST2` into account when
+ * canonicalizing `make_path`.
+ */
+ flags &= ~(GIT_MKDIR_SKIP_LAST2 | GIT_MKDIR_SKIP_LAST);
+
+ error = git_futils_mkdir_relative(relative,
+ parent_path.size ? parent_path.ptr : NULL, mode, flags, &opts);
+
+done:
+ git_buf_dispose(&make_path);
+ git_buf_dispose(&parent_path);
+ return error;
+}
+
+int git_futils_mkdir_r(const char *path, const mode_t mode)
+{
+ return git_futils_mkdir(path, mode, GIT_MKDIR_PATH);
+}
+
+int git_futils_mkdir_relative(
+ const char *relative_path,
+ const char *base,
+ mode_t mode,
+ uint32_t flags,
+ struct git_futils_mkdir_options *opts)
+{
+ git_buf make_path = GIT_BUF_INIT;
+ ssize_t root = 0, min_root_len;
+ char lastch = '/', *tail;
+ struct stat st;
+ struct git_futils_mkdir_options empty_opts = {0};
+ int error;
+
+ if (!opts)
+ opts = &empty_opts;
+
+ /* build path and find "root" where we should start calling mkdir */
+ if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0)
+ return -1;
+
+ if ((error = mkdir_canonicalize(&make_path, flags)) < 0 ||
+ make_path.size == 0)
+ goto done;
+
+ /* if we are not supposed to make the whole path, reset root */
+ if ((flags & GIT_MKDIR_PATH) == 0)
+ root = git_buf_rfind(&make_path, '/');
+
+ /* advance root past drive name or network mount prefix */
+ min_root_len = git_path_root(make_path.ptr);
+ if (root < min_root_len)
+ root = min_root_len;
+ while (root >= 0 && make_path.ptr[root] == '/')
+ ++root;
+
+ /* clip root to make_path length */
+ if (root > (ssize_t)make_path.size)
+ root = (ssize_t)make_path.size; /* i.e. NUL byte of string */
+ if (root < 0)
+ root = 0;
+
+ /* walk down tail of path making each directory */
+ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) {
+ bool mkdir_attempted = false;
+
+ /* advance tail to include next path component */
+ while (*tail == '/')
+ tail++;
+ while (*tail && *tail != '/')
+ tail++;
+
+ /* truncate path at next component */
+ lastch = *tail;
+ *tail = '\0';
+ st.st_mode = 0;
+
+ if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr))
+ continue;
+
+ /* See what's going on with this path component */
+ opts->perfdata.stat_calls++;
+
+retry_lstat:
+ if (p_lstat(make_path.ptr, &st) < 0) {
+ if (mkdir_attempted || errno != ENOENT) {
+ git_error_set(GIT_ERROR_OS, "cannot access component in path '%s'", make_path.ptr);
+ error = -1;
+ goto done;
+ }
+
+ git_error_clear();
+ opts->perfdata.mkdir_calls++;
+ mkdir_attempted = true;
+ if (p_mkdir(make_path.ptr, mode) < 0) {
+ if (errno == EEXIST)
+ goto retry_lstat;
+ git_error_set(GIT_ERROR_OS, "failed to make directory '%s'", make_path.ptr);
+ error = -1;
+ goto done;
+ }
+ } else {
+ if ((error = mkdir_validate_dir(
+ make_path.ptr, &st, mode, flags, opts)) < 0)
+ goto done;
+ }
+
+ /* chmod if requested and necessary */
+ if ((error = mkdir_validate_mode(
+ make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0)
+ goto done;
+
+ if (opts->dir_map && opts->pool) {
+ char *cache_path;
+ size_t alloc_size;
+
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1);
+ cache_path = git_pool_malloc(opts->pool, alloc_size);
+ GIT_ERROR_CHECK_ALLOC(cache_path);
+
+ memcpy(cache_path, make_path.ptr, make_path.size + 1);
+
+ if ((error = git_strmap_set(opts->dir_map, cache_path, cache_path)) < 0)
+ goto done;
+ }
+ }
+
+ error = 0;
+
+ /* check that full path really is a directory if requested & needed */
+ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
+ lastch != '\0') {
+ opts->perfdata.stat_calls++;
+
+ if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ git_error_set(GIT_ERROR_OS, "path is not a directory '%s'",
+ make_path.ptr);
+ error = GIT_ENOTFOUND;
+ }
+ }
+
+done:
+ git_buf_dispose(&make_path);
+ return error;
+}
+
+typedef struct {
+ const char *base;
+ size_t baselen;
+ uint32_t flags;
+ int depth;
+} futils__rmdir_data;
+
+#define FUTILS_MAX_DEPTH 100
+
+static int futils__error_cannot_rmdir(const char *path, const char *filemsg)
+{
+ if (filemsg)
+ git_error_set(GIT_ERROR_OS, "could not remove directory '%s': %s",
+ path, filemsg);
+ else
+ git_error_set(GIT_ERROR_OS, "could not remove directory '%s'", path);
+
+ return -1;
+}
+
+static int futils__rm_first_parent(git_buf *path, const char *ceiling)
+{
+ int error = GIT_ENOTFOUND;
+ struct stat st;
+
+ while (error == GIT_ENOTFOUND) {
+ git_buf_rtruncate_at_char(path, '/');
+
+ if (!path->size || git__prefixcmp(path->ptr, ceiling) != 0)
+ error = 0;
+ else if (p_lstat_posixly(path->ptr, &st) == 0) {
+ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
+ error = p_unlink(path->ptr);
+ else if (!S_ISDIR(st.st_mode))
+ error = -1; /* fail to remove non-regular file */
+ } else if (errno != ENOTDIR)
+ error = -1;
+ }
+
+ if (error)
+ futils__error_cannot_rmdir(path->ptr, "cannot remove parent");
+
+ return error;
+}
+
+static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
+{
+ int error = 0;
+ futils__rmdir_data *data = opaque;
+ struct stat st;
+
+ if (data->depth > FUTILS_MAX_DEPTH)
+ error = futils__error_cannot_rmdir(
+ path->ptr, "directory nesting too deep");
+
+ else if ((error = p_lstat_posixly(path->ptr, &st)) < 0) {
+ if (errno == ENOENT)
+ error = 0;
+ else if (errno == ENOTDIR) {
+ /* asked to remove a/b/c/d/e and a/b is a normal file */
+ if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0)
+ error = futils__rm_first_parent(path, data->base);
+ else
+ futils__error_cannot_rmdir(
+ path->ptr, "parent is not directory");
+ }
+ else
+ error = git_path_set_error(errno, path->ptr, "rmdir");
+ }
+
+ else if (S_ISDIR(st.st_mode)) {
+ data->depth++;
+
+ error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data);
+
+ data->depth--;
+
+ if (error < 0)
+ return error;
+
+ if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0)
+ return error;
+
+ if ((error = p_rmdir(path->ptr)) < 0) {
+ if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
+ (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY))
+ error = 0;
+ else
+ error = git_path_set_error(errno, path->ptr, "rmdir");
+ }
+ }
+
+ else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) {
+ if (p_unlink(path->ptr) < 0)
+ error = git_path_set_error(errno, path->ptr, "remove");
+ }
+
+ else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0)
+ error = futils__error_cannot_rmdir(path->ptr, "still present");
+
+ return error;
+}
+
+static int futils__rmdir_empty_parent(void *opaque, const char *path)
+{
+ futils__rmdir_data *data = opaque;
+ int error = 0;
+
+ if (strlen(path) <= data->baselen)
+ error = GIT_ITEROVER;
+
+ else if (p_rmdir(path) < 0) {
+ int en = errno;
+
+ if (en == ENOENT || en == ENOTDIR) {
+ /* do nothing */
+ } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0 &&
+ en == EBUSY) {
+ error = git_path_set_error(errno, path, "rmdir");
+ } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
+ error = GIT_ITEROVER;
+ } else {
+ error = git_path_set_error(errno, path, "rmdir");
+ }
+ }
+
+ return error;
+}
+
+int git_futils_rmdir_r(
+ const char *path, const char *base, uint32_t flags)
+{
+ int error;
+ git_buf fullpath = GIT_BUF_INIT;
+ futils__rmdir_data data;
+
+ /* build path and find "root" where we should start calling mkdir */
+ if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0)
+ return -1;
+
+ memset(&data, 0, sizeof(data));
+ data.base = base ? base : "";
+ data.baselen = base ? strlen(base) : 0;
+ data.flags = flags;
+
+ error = futils__rmdir_recurs_foreach(&data, &fullpath);
+
+ /* remove now-empty parents if requested */
+ if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0)
+ error = git_path_walk_up(
+ &fullpath, base, futils__rmdir_empty_parent, &data);
+
+ if (error == GIT_ITEROVER) {
+ git_error_clear();
+ error = 0;
+ }
+
+ git_buf_dispose(&fullpath);
+
+ return error;
+}
+
+int git_futils_fake_symlink(const char *target, const char *path)
+{
+ int retcode = GIT_ERROR;
+ int fd = git_futils_creat_withpath(path, 0755, 0644);
+ if (fd >= 0) {
+ retcode = p_write(fd, target, strlen(target));
+ p_close(fd);
+ }
+ return retcode;
+}
+
+static int cp_by_fd(int ifd, int ofd, bool close_fd_when_done)
+{
+ int error = 0;
+ char buffer[FILEIO_BUFSIZE];
+ ssize_t len = 0;
+
+ while (!error && (len = p_read(ifd, buffer, sizeof(buffer))) > 0)
+ /* p_write() does not have the same semantics as write(). It loops
+ * internally and will return 0 when it has completed writing.
+ */
+ error = p_write(ofd, buffer, len);
+
+ if (len < 0) {
+ git_error_set(GIT_ERROR_OS, "read error while copying file");
+ error = (int)len;
+ }
+
+ if (error < 0)
+ git_error_set(GIT_ERROR_OS, "write error while copying file");
+
+ if (close_fd_when_done) {
+ p_close(ifd);
+ p_close(ofd);
+ }
+
+ return error;
+}
+
+int git_futils_cp(const char *from, const char *to, mode_t filemode)
+{
+ int ifd, ofd;
+
+ if ((ifd = git_futils_open_ro(from)) < 0)
+ return ifd;
+
+ if ((ofd = p_open(to, O_WRONLY | O_CREAT | O_EXCL, filemode)) < 0) {
+ p_close(ifd);
+ return git_path_set_error(errno, to, "open for writing");
+ }
+
+ return cp_by_fd(ifd, ofd, true);
+}
+
+int git_futils_touch(const char *path, time_t *when)
+{
+ struct p_timeval times[2];
+ int ret;
+
+ times[0].tv_sec = times[1].tv_sec = when ? *when : time(NULL);
+ times[0].tv_usec = times[1].tv_usec = 0;
+
+ ret = p_utimes(path, times);
+
+ return (ret < 0) ? git_path_set_error(errno, path, "touch") : 0;
+}
+
+static int cp_link(const char *from, const char *to, size_t link_size)
+{
+ int error = 0;
+ ssize_t read_len;
+ char *link_data;
+ size_t alloc_size;
+
+ GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, link_size, 1);
+ link_data = git__malloc(alloc_size);
+ GIT_ERROR_CHECK_ALLOC(link_data);
+
+ read_len = p_readlink(from, link_data, link_size);
+ if (read_len != (ssize_t)link_size) {
+ git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", from);
+ error = -1;
+ }
+ else {
+ link_data[read_len] = '\0';
+
+ if (p_symlink(link_data, to) < 0) {
+ git_error_set(GIT_ERROR_OS, "could not symlink '%s' as '%s'",
+ link_data, to);
+ error = -1;
+ }
+ }
+
+ git__free(link_data);
+ return error;
+}
+
+typedef struct {
+ const char *to_root;
+ git_buf to;
+ ssize_t from_prefix;
+ uint32_t flags;
+ uint32_t mkdir_flags;
+ mode_t dirmode;
+} cp_r_info;
+
+#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10)
+
+static int _cp_r_mkdir(cp_r_info *info, git_buf *from)
+{
+ int error = 0;
+
+ /* create root directory the first time we need to create a directory */
+ if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) {
+ error = git_futils_mkdir(
+ info->to_root, info->dirmode,
+ (info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0);
+
+ info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT;
+ }
+
+ /* create directory with root as base to prevent excess chmods */
+ if (!error)
+ error = git_futils_mkdir_relative(
+ from->ptr + info->from_prefix, info->to_root,
+ info->dirmode, info->mkdir_flags, NULL);
+
+ return error;
+}
+
+static int _cp_r_callback(void *ref, git_buf *from)
+{
+ int error = 0;
+ cp_r_info *info = ref;
+ struct stat from_st, to_st;
+ bool exists = false;
+
+ if ((info->flags & GIT_CPDIR_COPY_DOTFILES) == 0 &&
+ from->ptr[git_path_basename_offset(from)] == '.')
+ return 0;
+
+ if ((error = git_buf_joinpath(
+ &info->to, info->to_root, from->ptr + info->from_prefix)) < 0)
+ return error;
+
+ if (!(error = git_path_lstat(info->to.ptr, &to_st)))
+ exists = true;
+ else if (error != GIT_ENOTFOUND)
+ return error;
+ else {
+ git_error_clear();
+ error = 0;
+ }
+
+ if ((error = git_path_lstat(from->ptr, &from_st)) < 0)
+ return error;
+
+ if (S_ISDIR(from_st.st_mode)) {
+ mode_t oldmode = info->dirmode;
+
+ /* if we are not chmod'ing, then overwrite dirmode */
+ if ((info->flags & GIT_CPDIR_CHMOD_DIRS) == 0)
+ info->dirmode = from_st.st_mode;
+
+ /* make directory now if CREATE_EMPTY_DIRS is requested and needed */
+ if (!exists && (info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) != 0)
+ error = _cp_r_mkdir(info, from);
+
+ /* recurse onto target directory */
+ if (!error && (!exists || S_ISDIR(to_st.st_mode)))
+ error = git_path_direach(from, 0, _cp_r_callback, info);
+
+ if (oldmode != 0)
+ info->dirmode = oldmode;
+
+ return error;
+ }
+
+ if (exists) {
+ if ((info->flags & GIT_CPDIR_OVERWRITE) == 0)
+ return 0;
+
+ if (p_unlink(info->to.ptr) < 0) {
+ git_error_set(GIT_ERROR_OS, "cannot overwrite existing file '%s'",
+ info->to.ptr);
+ return GIT_EEXISTS;
+ }
+ }
+
+ /* Done if this isn't a regular file or a symlink */
+ if (!S_ISREG(from_st.st_mode) &&
+ (!S_ISLNK(from_st.st_mode) ||
+ (info->flags & GIT_CPDIR_COPY_SYMLINKS) == 0))
+ return 0;
+
+ /* Make container directory on demand if needed */
+ if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 &&
+ (error = _cp_r_mkdir(info, from)) < 0)
+ return error;
+
+ /* make symlink or regular file */
+ if (info->flags & GIT_CPDIR_LINK_FILES) {
+ if ((error = p_link(from->ptr, info->to.ptr)) < 0)
+ git_error_set(GIT_ERROR_OS, "failed to link '%s'", from->ptr);
+ } else if (S_ISLNK(from_st.st_mode)) {
+ error = cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size);
+ } else {
+ mode_t usemode = from_st.st_mode;
+
+ if ((info->flags & GIT_CPDIR_SIMPLE_TO_MODE) != 0)
+ usemode = GIT_PERMS_FOR_WRITE(usemode);
+
+ error = git_futils_cp(from->ptr, info->to.ptr, usemode);
+ }
+
+ return error;
+}
+
+int git_futils_cp_r(
+ const char *from,
+ const char *to,
+ uint32_t flags,
+ mode_t dirmode)
+{
+ int error;
+ git_buf path = GIT_BUF_INIT;
+ cp_r_info info;
+
+ if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */
+ return -1;
+
+ memset(&info, 0, sizeof(info));
+ info.to_root = to;
+ info.flags = flags;
+ info.dirmode = dirmode;
+ info.from_prefix = path.size;
+ git_buf_init(&info.to, 0);
+
+ /* precalculate mkdir flags */
+ if ((flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0) {
+ /* if not creating empty dirs, then use mkdir to create the path on
+ * demand right before files are copied.
+ */
+ info.mkdir_flags = GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST;
+ if ((flags & GIT_CPDIR_CHMOD_DIRS) != 0)
+ info.mkdir_flags |= GIT_MKDIR_CHMOD_PATH;
+ } else {
+ /* otherwise, we will do simple mkdir as directories are encountered */
+ info.mkdir_flags =
+ ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) ? GIT_MKDIR_CHMOD : 0;
+ }
+
+ error = _cp_r_callback(&info, &path);
+
+ git_buf_dispose(&path);
+ git_buf_dispose(&info.to);
+
+ return error;
+}
+
+int git_futils_filestamp_check(
+ git_futils_filestamp *stamp, const char *path)
+{
+ struct stat st;
+
+ /* if the stamp is NULL, then always reload */
+ if (stamp == NULL)
+ return 1;
+
+ if (p_stat(path, &st) < 0)
+ return GIT_ENOTFOUND;
+
+ if (stamp->mtime.tv_sec == st.st_mtime &&
+#if defined(GIT_USE_NSEC)
+ stamp->mtime.tv_nsec == st.st_mtime_nsec &&
+#endif
+ stamp->size == (uint64_t)st.st_size &&
+ stamp->ino == (unsigned int)st.st_ino)
+ return 0;
+
+ stamp->mtime.tv_sec = st.st_mtime;
+#if defined(GIT_USE_NSEC)
+ stamp->mtime.tv_nsec = st.st_mtime_nsec;
+#endif
+ stamp->size = (uint64_t)st.st_size;
+ stamp->ino = (unsigned int)st.st_ino;
+
+ return 1;
+}
+
+void git_futils_filestamp_set(
+ git_futils_filestamp *target, const git_futils_filestamp *source)
+{
+ assert(target);
+
+ if (source)
+ memcpy(target, source, sizeof(*target));
+ else
+ memset(target, 0, sizeof(*target));
+}
+
+
+void git_futils_filestamp_set_from_stat(
+ git_futils_filestamp *stamp, struct stat *st)
+{
+ if (st) {
+ stamp->mtime.tv_sec = st->st_mtime;
+#if defined(GIT_USE_NSEC)
+ stamp->mtime.tv_nsec = st->st_mtime_nsec;
+#else
+ stamp->mtime.tv_nsec = 0;
+#endif
+ stamp->size = (uint64_t)st->st_size;
+ stamp->ino = (unsigned int)st->st_ino;
+ } else {
+ memset(stamp, 0, sizeof(*stamp));
+ }
+}
+
+int git_futils_fsync_dir(const char *path)
+{
+#ifdef GIT_WIN32
+ GIT_UNUSED(path);
+ return 0;
+#else
+ int fd, error = -1;
+
+ if ((fd = p_open(path, O_RDONLY)) < 0) {
+ git_error_set(GIT_ERROR_OS, "failed to open directory '%s' for fsync", path);
+ return -1;
+ }
+
+ if ((error = p_fsync(fd)) < 0)
+ git_error_set(GIT_ERROR_OS, "failed to fsync directory '%s'", path);
+
+ p_close(fd);
+ return error;
+#endif
+}
+
+int git_futils_fsync_parent(const char *path)
+{
+ char *parent;
+ int error;
+
+ if ((parent = git_path_dirname(path)) == NULL)
+ return -1;
+
+ error = git_futils_fsync_dir(parent);
+ git__free(parent);
+ return error;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_futils_h__
+#define INCLUDE_futils_h__
+
+#include "common.h"
+
+#include "map.h"
+#include "posix.h"
+#include "path.h"
+#include "pool.h"
+#include "strmap.h"
+#include "oid.h"
+
+/**
+ * Filebuffer methods
+ *
+ * Read whole files into an in-memory buffer for processing
+ */
+extern int git_futils_readbuffer(git_buf *obj, const char *path);
+extern int git_futils_readbuffer_updated(
+ git_buf *obj, const char *path, git_oid *checksum, int *updated);
+extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len);
+
+/* Additional constants for `git_futils_writebuffer`'s `open_flags`. We
+ * support these internally and they will be removed before the `open` call.
+ */
+#ifndef O_FSYNC
+# define O_FSYNC (1 << 31)
+#endif
+
+extern int git_futils_writebuffer(
+ const git_buf *buf, const char *path, int open_flags, mode_t mode);
+
+/**
+ * File utils
+ *
+ * These are custom filesystem-related helper methods. They are
+ * rather high level, and wrap the underlying POSIX methods
+ *
+ * All these methods return 0 on success,
+ * or an error code on failure and an error message is set.
+ */
+
+/**
+ * Create and open a file, while also
+ * creating all the folders in its path
+ */
+extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode);
+
+/**
+ * Create and open a process-locked file
+ */
+extern int git_futils_creat_locked(const char *path, const mode_t mode);
+
+/**
+ * Create and open a process-locked file, while
+ * also creating all the folders in its path
+ */
+extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode);
+
+/**
+ * Create a path recursively.
+ */
+extern int git_futils_mkdir_r(const char *path, const mode_t mode);
+
+/**
+ * Flags to pass to `git_futils_mkdir`.
+ *
+ * * GIT_MKDIR_EXCL is "exclusive" - i.e. generate an error if dir exists.
+ * * GIT_MKDIR_PATH says to make all components in the path.
+ * * GIT_MKDIR_CHMOD says to chmod the final directory entry after creation
+ * * GIT_MKDIR_CHMOD_PATH says to chmod each directory component in the path
+ * * GIT_MKDIR_SKIP_LAST says to leave off the last element of the path
+ * * GIT_MKDIR_SKIP_LAST2 says to leave off the last 2 elements of the path
+ * * GIT_MKDIR_VERIFY_DIR says confirm final item is a dir, not just EEXIST
+ * * GIT_MKDIR_REMOVE_FILES says to remove files and recreate dirs
+ * * GIT_MKDIR_REMOVE_SYMLINKS says to remove symlinks and recreate dirs
+ *
+ * Note that the chmod options will be executed even if the directory already
+ * exists, unless GIT_MKDIR_EXCL is given.
+ */
+typedef enum {
+ GIT_MKDIR_EXCL = 1,
+ GIT_MKDIR_PATH = 2,
+ GIT_MKDIR_CHMOD = 4,
+ GIT_MKDIR_CHMOD_PATH = 8,
+ GIT_MKDIR_SKIP_LAST = 16,
+ GIT_MKDIR_SKIP_LAST2 = 32,
+ GIT_MKDIR_VERIFY_DIR = 64,
+ GIT_MKDIR_REMOVE_FILES = 128,
+ GIT_MKDIR_REMOVE_SYMLINKS = 256,
+} git_futils_mkdir_flags;
+
+struct git_futils_mkdir_perfdata
+{
+ size_t stat_calls;
+ size_t mkdir_calls;
+ size_t chmod_calls;
+};
+
+struct git_futils_mkdir_options
+{
+ git_strmap *dir_map;
+ git_pool *pool;
+ struct git_futils_mkdir_perfdata perfdata;
+};
+
+/**
+ * Create a directory or entire path.
+ *
+ * This makes a directory (and the entire path leading up to it if requested),
+ * and optionally chmods the directory immediately after (or each part of the
+ * path if requested).
+ *
+ * @param path The path to create, relative to base.
+ * @param base Root for relative path. These directories will never be made.
+ * @param mode The mode to use for created directories.
+ * @param flags Combination of the mkdir flags above.
+ * @param opts Extended options, or null.
+ * @return 0 on success, else error code
+ */
+extern int git_futils_mkdir_relative(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
+
+/**
+ * Create a directory or entire path. Similar to `git_futils_mkdir_relative`
+ * without performance data.
+ */
+extern int git_futils_mkdir(const char *path, mode_t mode, uint32_t flags);
+
+/**
+ * Create all the folders required to contain
+ * the full path of a file
+ */
+extern int git_futils_mkpath2file(const char *path, const mode_t mode);
+
+/**
+ * Flags to pass to `git_futils_rmdir_r`.
+ *
+ * * GIT_RMDIR_EMPTY_HIERARCHY - the default; remove hierarchy of empty
+ * dirs and generate error if any files are found.
+ * * GIT_RMDIR_REMOVE_FILES - attempt to remove files in the hierarchy.
+ * * GIT_RMDIR_SKIP_NONEMPTY - skip non-empty directories with no error.
+ * * GIT_RMDIR_EMPTY_PARENTS - remove containing directories up to base
+ * if removing this item leaves them empty
+ * * GIT_RMDIR_REMOVE_BLOCKERS - remove blocking file that causes ENOTDIR
+ * * GIT_RMDIR_SKIP_ROOT - don't remove root directory itself
+ */
+typedef enum {
+ GIT_RMDIR_EMPTY_HIERARCHY = 0,
+ GIT_RMDIR_REMOVE_FILES = (1 << 0),
+ GIT_RMDIR_SKIP_NONEMPTY = (1 << 1),
+ GIT_RMDIR_EMPTY_PARENTS = (1 << 2),
+ GIT_RMDIR_REMOVE_BLOCKERS = (1 << 3),
+ GIT_RMDIR_SKIP_ROOT = (1 << 4),
+} git_futils_rmdir_flags;
+
+/**
+ * Remove path and any files and directories beneath it.
+ *
+ * @param path Path to the top level directory to process.
+ * @param base Root for relative path.
+ * @param flags Combination of git_futils_rmdir_flags values
+ * @return 0 on success; -1 on error.
+ */
+extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags);
+
+/**
+ * Create and open a temporary file with a `_git2_` suffix.
+ * Writes the filename into path_out.
+ * @return On success, an open file descriptor, else an error code < 0.
+ */
+extern int git_futils_mktmp(git_buf *path_out, const char *filename, mode_t mode);
+
+/**
+ * Move a file on the filesystem, create the
+ * destination path if it doesn't exist
+ */
+extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode);
+
+/**
+ * Copy a file
+ *
+ * The filemode will be used for the newly created file.
+ */
+extern int git_futils_cp(
+ const char *from,
+ const char *to,
+ mode_t filemode);
+
+/**
+ * Set the files atime and mtime to the given time, or the current time
+ * if `ts` is NULL.
+ */
+extern int git_futils_touch(const char *path, time_t *when);
+
+/**
+ * Flags that can be passed to `git_futils_cp_r`.
+ *
+ * - GIT_CPDIR_CREATE_EMPTY_DIRS: create directories even if there are no
+ * files under them (otherwise directories will only be created lazily
+ * when a file inside them is copied).
+ * - GIT_CPDIR_COPY_SYMLINKS: copy symlinks, otherwise they are ignored.
+ * - GIT_CPDIR_COPY_DOTFILES: copy files with leading '.', otherwise ignored.
+ * - GIT_CPDIR_OVERWRITE: overwrite pre-existing files with source content,
+ * otherwise they are silently skipped.
+ * - GIT_CPDIR_CHMOD_DIRS: explicitly chmod directories to `dirmode`
+ * - GIT_CPDIR_SIMPLE_TO_MODE: default tries to replicate the mode of the
+ * source file to the target; with this flag, always use 0666 (or 0777 if
+ * source has exec bits set) for target.
+ * - GIT_CPDIR_LINK_FILES will try to use hardlinks for the files
+ */
+typedef enum {
+ GIT_CPDIR_CREATE_EMPTY_DIRS = (1u << 0),
+ GIT_CPDIR_COPY_SYMLINKS = (1u << 1),
+ GIT_CPDIR_COPY_DOTFILES = (1u << 2),
+ GIT_CPDIR_OVERWRITE = (1u << 3),
+ GIT_CPDIR_CHMOD_DIRS = (1u << 4),
+ GIT_CPDIR_SIMPLE_TO_MODE = (1u << 5),
+ GIT_CPDIR_LINK_FILES = (1u << 6),
+} git_futils_cpdir_flags;
+
+/**
+ * Copy a directory tree.
+ *
+ * This copies directories and files from one root to another. You can
+ * pass a combinationof GIT_CPDIR flags as defined above.
+ *
+ * If you pass the CHMOD flag, then the dirmode will be applied to all
+ * directories that are created during the copy, overiding the natural
+ * permissions. If you do not pass the CHMOD flag, then the dirmode
+ * will actually be copied from the source files and the `dirmode` arg
+ * will be ignored.
+ */
+extern int git_futils_cp_r(
+ const char *from,
+ const char *to,
+ uint32_t flags,
+ mode_t dirmode);
+
+/**
+ * Open a file readonly and set error if needed.
+ */
+extern int git_futils_open_ro(const char *path);
+
+/**
+ * Truncate a file, creating it if it doesn't exist.
+ */
+extern int git_futils_truncate(const char *path, int mode);
+
+/**
+ * Get the filesize in bytes of a file
+ */
+extern int git_futils_filesize(uint64_t *out, git_file fd);
+
+#define GIT_PERMS_IS_EXEC(MODE) (((MODE) & 0111) != 0)
+#define GIT_PERMS_CANONICAL(MODE) (GIT_PERMS_IS_EXEC(MODE) ? 0755 : 0644)
+#define GIT_PERMS_FOR_WRITE(MODE) (GIT_PERMS_IS_EXEC(MODE) ? 0777 : 0666)
+
+#define GIT_MODE_PERMS_MASK 0777
+#define GIT_MODE_TYPE_MASK 0170000
+#define GIT_MODE_TYPE(MODE) ((MODE) & GIT_MODE_TYPE_MASK)
+#define GIT_MODE_ISBLOB(MODE) (GIT_MODE_TYPE(MODE) == GIT_MODE_TYPE(GIT_FILEMODE_BLOB))
+
+/**
+ * Convert a mode_t from the OS to a legal git mode_t value.
+ */
+extern mode_t git_futils_canonical_mode(mode_t raw_mode);
+
+
+/**
+ * Read-only map all or part of a file into memory.
+ * When possible this function should favor a virtual memory
+ * style mapping over some form of malloc()+read(), as the
+ * data access will be random and is not likely to touch the
+ * majority of the region requested.
+ *
+ * @param out buffer to populate with the mapping information.
+ * @param fd open descriptor to configure the mapping from.
+ * @param begin first byte to map, this should be page aligned.
+ * @param len number of bytes to map.
+ * @return
+ * - 0 on success;
+ * - -1 on error.
+ */
+extern int git_futils_mmap_ro(
+ git_map *out,
+ git_file fd,
+ off64_t begin,
+ size_t len);
+
+/**
+ * Read-only map an entire file.
+ *
+ * @param out buffer to populate with the mapping information.
+ * @param path path to file to be opened.
+ * @return
+ * - 0 on success;
+ * - GIT_ENOTFOUND if not found;
+ * - -1 on an unspecified OS related error.
+ */
+extern int git_futils_mmap_ro_file(
+ git_map *out,
+ const char *path);
+
+/**
+ * Release the memory associated with a previous memory mapping.
+ * @param map the mapping description previously configured.
+ */
+extern void git_futils_mmap_free(git_map *map);
+
+/**
+ * Create a "fake" symlink (text file containing the target path).
+ *
+ * @param target original symlink target
+ * @param path symlink file to be created
+ * @return 0 on success, -1 on error
+ */
+extern int git_futils_fake_symlink(const char *target, const char *path);
+
+/**
+ * A file stamp represents a snapshot of information about a file that can
+ * be used to test if the file changes. This portable implementation is
+ * based on stat data about that file, but it is possible that OS specific
+ * versions could be implemented in the future.
+ */
+typedef struct {
+ struct timespec mtime;
+ uint64_t size;
+ unsigned int ino;
+} git_futils_filestamp;
+
+/**
+ * Compare stat information for file with reference info.
+ *
+ * This function updates the file stamp to current data for the given path
+ * and returns 0 if the file is up-to-date relative to the prior setting,
+ * 1 if the file has been changed, or GIT_ENOTFOUND if the file doesn't
+ * exist. This will not call git_error_set, so you must set the error if you
+ * plan to return an error.
+ *
+ * @param stamp File stamp to be checked
+ * @param path Path to stat and check if changed
+ * @return 0 if up-to-date, 1 if out-of-date, GIT_ENOTFOUND if cannot stat
+ */
+extern int git_futils_filestamp_check(
+ git_futils_filestamp *stamp, const char *path);
+
+/**
+ * Set or reset file stamp data
+ *
+ * This writes the target file stamp. If the source is NULL, this will set
+ * the target stamp to values that will definitely be out of date. If the
+ * source is not NULL, this copies the source values to the target.
+ *
+ * @param tgt File stamp to write to
+ * @param src File stamp to copy from or NULL to clear the target
+ */
+extern void git_futils_filestamp_set(
+ git_futils_filestamp *tgt, const git_futils_filestamp *src);
+
+/**
+ * Set file stamp data from stat structure
+ */
+extern void git_futils_filestamp_set_from_stat(
+ git_futils_filestamp *stamp, struct stat *st);
+
+/**
+ * `fsync` the parent directory of the given path, if `fsync` is
+ * supported for directories on this platform.
+ *
+ * @param path Path of the directory to sync.
+ * @return 0 on success, -1 on error
+ */
+extern int git_futils_fsync_dir(const char *path);
+
+/**
+ * `fsync` the parent directory of the given path, if `fsync` is
+ * supported for directories on this platform.
+ *
+ * @param path Path of the file whose parent directory should be synced.
+ * @return 0 on success, -1 on error
+ */
+extern int git_futils_fsync_parent(const char *path);
+
+#endif
#include "sysdir.h"
#include "filter.h"
#include "merge_driver.h"
+#include "pool.h"
#include "streams/registry.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
git_stream_registry_global_init,
git_openssl_stream_global_init,
git_mbedtls_stream_global_init,
- git_mwindow_global_init
+ git_mwindow_global_init,
+ git_pool_global_init
};
static git_global_shutdown_fn git__shutdown_callbacks[ARRAY_SIZE(git__init_callbacks)];
*/
#if defined(GIT_THREADS) && defined(GIT_WIN32)
-static DWORD _tls_index;
+static DWORD _fls_index;
static volatile LONG _mutex = 0;
+static void WINAPI fls_free(void *st)
+{
+ git__global_state_cleanup(st);
+ git__free(st);
+}
+
static int synchronized_threads_init(void)
{
int error;
- _tls_index = TlsAlloc();
+ if ((_fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
+ return -1;
git_threads_init();
if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
shutdown_common();
- git__free_tls_data();
-
- TlsFree(_tls_index);
+ FlsFree(_fls_index);
git_mutex_free(&git__mwindow_mutex);
#if defined(GIT_MSVC_CRTDBG)
assert(git_atomic_get(&git__n_inits) > 0);
- if ((ptr = TlsGetValue(_tls_index)) != NULL)
+ if ((ptr = FlsGetValue(_fls_index)) != NULL)
return ptr;
ptr = git__calloc(1, sizeof(git_global_st));
git_buf_init(&ptr->error_buf, 0);
- TlsSetValue(_tls_index, ptr);
+ FlsSetValue(_fls_index, ptr);
return ptr;
}
-/**
- * Free the TLS data associated with this thread.
- * This should only be used by the thread as it
- * is exiting.
- */
-void git__free_tls_data(void)
-{
- void *ptr = TlsGetValue(_tls_index);
- if (!ptr)
- return;
-
- git__global_state_cleanup(ptr);
- git__free(ptr);
- TlsSetValue(_tls_index, NULL);
-}
-
-BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
-{
- GIT_UNUSED(hInstDll);
- GIT_UNUSED(lpvReserved);
-
- /* This is how Windows lets us know our thread is being shut down */
- if (fdwReason == DLL_THREAD_DETACH) {
- git__free_tls_data();
- }
-
- /*
- * Windows pays attention to this during library loading. We don't do anything
- * so we trivially succeed.
- */
- return TRUE;
-}
-
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
static pthread_key_t _tls_key;
extern void git__on_shutdown(git_global_shutdown_fn callback);
-extern void git__free_tls_data(void);
-
extern const char *git_libgit2__user_agent(void);
extern const char *git_libgit2__ssl_ciphers(void);
#include "hash.h"
+int git_hash_global_init(void)
+{
+ return git_hash_sha1_global_init();
+}
+
+int git_hash_ctx_init(git_hash_ctx *ctx)
+{
+ int error;
+
+ if ((error = git_hash_sha1_ctx_init(&ctx->sha1)) < 0)
+ return error;
+
+ ctx->algo = GIT_HASH_ALGO_SHA1;
+
+ return 0;
+}
+
+void git_hash_ctx_cleanup(git_hash_ctx *ctx)
+{
+ switch (ctx->algo) {
+ case GIT_HASH_ALGO_SHA1:
+ git_hash_sha1_ctx_cleanup(&ctx->sha1);
+ return;
+ default:
+ assert(0);
+ }
+}
+
+int git_hash_init(git_hash_ctx *ctx)
+{
+ switch (ctx->algo) {
+ case GIT_HASH_ALGO_SHA1:
+ return git_hash_sha1_init(&ctx->sha1);
+ default:
+ assert(0);
+ return -1;
+ }
+}
+
+int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
+{
+ switch (ctx->algo) {
+ case GIT_HASH_ALGO_SHA1:
+ return git_hash_sha1_update(&ctx->sha1, data, len);
+ default:
+ assert(0);
+ return -1;
+ }
+}
+
+int git_hash_final(git_oid *out, git_hash_ctx *ctx)
+{
+ switch (ctx->algo) {
+ case GIT_HASH_ALGO_SHA1:
+ return git_hash_sha1_final(out, &ctx->sha1);
+ default:
+ assert(0);
+ return -1;
+ }
+}
+
int git_hash_buf(git_oid *out, const void *data, size_t len)
{
git_hash_ctx ctx;
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
+
#ifndef INCLUDE_hash_h__
#define INCLUDE_hash_h__
#include "git2/oid.h"
-typedef struct git_hash_prov git_hash_prov;
-typedef struct git_hash_ctx git_hash_ctx;
+typedef struct {
+ void *data;
+ size_t len;
+} git_buf_vec;
-int git_hash_ctx_init(git_hash_ctx *ctx);
-void git_hash_ctx_cleanup(git_hash_ctx *ctx);
+typedef enum {
+ GIT_HASH_ALGO_UNKNOWN = 0,
+ GIT_HASH_ALGO_SHA1,
+} git_hash_algo_t;
-#if defined(GIT_SHA1_COLLISIONDETECT)
-# include "hash/hash_collisiondetect.h"
-#elif defined(GIT_SHA1_COMMON_CRYPTO)
-# include "hash/hash_common_crypto.h"
-#elif defined(GIT_SHA1_OPENSSL)
-# include "hash/hash_openssl.h"
-#elif defined(GIT_SHA1_WIN32)
-# include "hash/hash_win32.h"
-#elif defined(GIT_SHA1_MBEDTLS)
-# include "hash/hash_mbedtls.h"
-#else
-# include "hash/hash_generic.h"
-#endif
+#include "hash/sha1.h"
+
+typedef struct git_hash_ctx {
+ union {
+ git_hash_sha1_ctx sha1;
+ };
+ git_hash_algo_t algo;
+} git_hash_ctx;
int git_hash_global_init(void);
-typedef struct {
- void *data;
- size_t len;
-} git_buf_vec;
+int git_hash_ctx_init(git_hash_ctx *ctx);
+void git_hash_ctx_cleanup(git_hash_ctx *ctx);
int git_hash_init(git_hash_ctx *c);
int git_hash_update(git_hash_ctx *c, const void *data, size_t len);
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_hash_hash_collisiondetect_h__
-#define INCLUDE_hash_hash_collisiondetect_h__
-
-#include "hash.h"
-#include "sha1dc/sha1.h"
-
-struct git_hash_ctx {
- SHA1_CTX c;
-};
-
-#define git_hash_ctx_init(ctx) git_hash_init(ctx)
-#define git_hash_ctx_cleanup(ctx)
-
-GIT_INLINE(int) git_hash_global_init(void)
-{
- return 0;
-}
-
-GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
-{
- assert(ctx);
- SHA1DCInit(&ctx->c);
- return 0;
-}
-
-GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
-{
- assert(ctx);
- SHA1DCUpdate(&ctx->c, data, len);
- return 0;
-}
-
-GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
-{
- assert(ctx);
- if (SHA1DCFinal(out->id, &ctx->c)) {
- git_error_set(GIT_ERROR_SHA1, "SHA1 collision attack detected");
- return -1;
- }
-
- return 0;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_hash_hash_common_crypto_h__
-#define INCLUDE_hash_hash_common_crypto_h__
-
-#include "hash.h"
-
-#include <CommonCrypto/CommonDigest.h>
-
-struct git_hash_ctx {
- CC_SHA1_CTX c;
-};
-
-#define CC_LONG_MAX ((CC_LONG)-1)
-
-#define git_hash_ctx_init(ctx) git_hash_init(ctx)
-#define git_hash_ctx_cleanup(ctx)
-
-GIT_INLINE(int) git_hash_global_init(void)
-{
- return 0;
-}
-
-GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
-{
- assert(ctx);
- CC_SHA1_Init(&ctx->c);
- return 0;
-}
-
-GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *_data, size_t len)
-{
- const unsigned char *data = _data;
-
- assert(ctx);
-
- while (len > 0) {
- CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len;
-
- CC_SHA1_Update(&ctx->c, data, chunk);
-
- data += chunk;
- len -= chunk;
- }
-
- return 0;
-}
-
-GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
-{
- assert(ctx);
- CC_SHA1_Final(out->id, &ctx->c);
- return 0;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "hash_generic.h"
-
-#include "hash.h"
-
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-
-/*
- * Force usage of rol or ror by selecting the one with the smaller constant.
- * It _can_ generate slightly smaller code (a constant of 1 is special), but
- * perhaps more importantly it's possibly faster on any uarch that does a
- * rotate with a loop.
- */
-
-#define SHA_ASM(op, x, n) (__extension__ ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; }))
-#define SHA_ROL(x,n) SHA_ASM("rol", x, n)
-#define SHA_ROR(x,n) SHA_ASM("ror", x, n)
-
-#else
-
-#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r)))
-#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n))
-#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n)
-
-#endif
-
-/*
- * If you have 32 registers or more, the compiler can (and should)
- * try to change the array[] accesses into registers. However, on
- * machines with less than ~25 registers, that won't really work,
- * and at least gcc will make an unholy mess of it.
- *
- * So to avoid that mess which just slows things down, we force
- * the stores to memory to actually happen (we might be better off
- * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
- * suggested by Artur Skawina - that will also make gcc unable to
- * try to do the silly "optimize away loads" part because it won't
- * see what the value will be).
- *
- * Ben Herrenschmidt reports that on PPC, the C version comes close
- * to the optimized asm with this (ie on PPC you don't want that
- * 'volatile', since there are lots of registers).
- *
- * On ARM we get the best code generation by forcing a full memory barrier
- * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
- * the stack frame size simply explode and performance goes down the drain.
- */
-
-#if defined(__i386__) || defined(__x86_64__)
- #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
-#elif defined(__GNUC__) && defined(__arm__)
- #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
-#else
- #define setW(x, val) (W(x) = (val))
-#endif
-
-/*
- * Performance might be improved if the CPU architecture is OK with
- * unaligned 32-bit loads and a fast ntohl() is available.
- * Otherwise fall back to byte loads and shifts which is portable,
- * and is faster on architectures with memory alignment issues.
- */
-
-#if defined(__i386__) || defined(__x86_64__) || \
- defined(_M_IX86) || defined(_M_X64) || \
- defined(__ppc__) || defined(__ppc64__) || \
- defined(__powerpc__) || defined(__powerpc64__) || \
- defined(__s390__) || defined(__s390x__)
-
-#define get_be32(p) ntohl(*(const unsigned int *)(p))
-#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
-
-#else
-
-#define get_be32(p) ( \
- (*((const unsigned char *)(p) + 0) << 24) | \
- (*((const unsigned char *)(p) + 1) << 16) | \
- (*((const unsigned char *)(p) + 2) << 8) | \
- (*((const unsigned char *)(p) + 3) << 0) )
-#define put_be32(p, v) do { \
- unsigned int __v = (v); \
- *((unsigned char *)(p) + 0) = __v >> 24; \
- *((unsigned char *)(p) + 1) = __v >> 16; \
- *((unsigned char *)(p) + 2) = __v >> 8; \
- *((unsigned char *)(p) + 3) = __v >> 0; } while (0)
-
-#endif
-
-/* This "rolls" over the 512-bit array */
-#define W(x) (array[(x)&15])
-
-/*
- * Where do we get the source from? The first 16 iterations get it from
- * the input data, the next mix it from the 512-bit array.
- */
-#define SHA_SRC(t) get_be32(data + t)
-#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
-
-#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
- unsigned int TEMP = input(t); setW(t, TEMP); \
- E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \
- B = SHA_ROR(B, 2); } while (0)
-
-#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
-#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
-#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
-#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
-#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
-
-static void hash__block(git_hash_ctx *ctx, const unsigned int *data)
-{
- unsigned int A,B,C,D,E;
- unsigned int array[16];
-
- A = ctx->H[0];
- B = ctx->H[1];
- C = ctx->H[2];
- D = ctx->H[3];
- E = ctx->H[4];
-
- /* Round 1 - iterations 0-16 take their input from 'data' */
- T_0_15( 0, A, B, C, D, E);
- T_0_15( 1, E, A, B, C, D);
- T_0_15( 2, D, E, A, B, C);
- T_0_15( 3, C, D, E, A, B);
- T_0_15( 4, B, C, D, E, A);
- T_0_15( 5, A, B, C, D, E);
- T_0_15( 6, E, A, B, C, D);
- T_0_15( 7, D, E, A, B, C);
- T_0_15( 8, C, D, E, A, B);
- T_0_15( 9, B, C, D, E, A);
- T_0_15(10, A, B, C, D, E);
- T_0_15(11, E, A, B, C, D);
- T_0_15(12, D, E, A, B, C);
- T_0_15(13, C, D, E, A, B);
- T_0_15(14, B, C, D, E, A);
- T_0_15(15, A, B, C, D, E);
-
- /* Round 1 - tail. Input from 512-bit mixing array */
- T_16_19(16, E, A, B, C, D);
- T_16_19(17, D, E, A, B, C);
- T_16_19(18, C, D, E, A, B);
- T_16_19(19, B, C, D, E, A);
-
- /* Round 2 */
- T_20_39(20, A, B, C, D, E);
- T_20_39(21, E, A, B, C, D);
- T_20_39(22, D, E, A, B, C);
- T_20_39(23, C, D, E, A, B);
- T_20_39(24, B, C, D, E, A);
- T_20_39(25, A, B, C, D, E);
- T_20_39(26, E, A, B, C, D);
- T_20_39(27, D, E, A, B, C);
- T_20_39(28, C, D, E, A, B);
- T_20_39(29, B, C, D, E, A);
- T_20_39(30, A, B, C, D, E);
- T_20_39(31, E, A, B, C, D);
- T_20_39(32, D, E, A, B, C);
- T_20_39(33, C, D, E, A, B);
- T_20_39(34, B, C, D, E, A);
- T_20_39(35, A, B, C, D, E);
- T_20_39(36, E, A, B, C, D);
- T_20_39(37, D, E, A, B, C);
- T_20_39(38, C, D, E, A, B);
- T_20_39(39, B, C, D, E, A);
-
- /* Round 3 */
- T_40_59(40, A, B, C, D, E);
- T_40_59(41, E, A, B, C, D);
- T_40_59(42, D, E, A, B, C);
- T_40_59(43, C, D, E, A, B);
- T_40_59(44, B, C, D, E, A);
- T_40_59(45, A, B, C, D, E);
- T_40_59(46, E, A, B, C, D);
- T_40_59(47, D, E, A, B, C);
- T_40_59(48, C, D, E, A, B);
- T_40_59(49, B, C, D, E, A);
- T_40_59(50, A, B, C, D, E);
- T_40_59(51, E, A, B, C, D);
- T_40_59(52, D, E, A, B, C);
- T_40_59(53, C, D, E, A, B);
- T_40_59(54, B, C, D, E, A);
- T_40_59(55, A, B, C, D, E);
- T_40_59(56, E, A, B, C, D);
- T_40_59(57, D, E, A, B, C);
- T_40_59(58, C, D, E, A, B);
- T_40_59(59, B, C, D, E, A);
-
- /* Round 4 */
- T_60_79(60, A, B, C, D, E);
- T_60_79(61, E, A, B, C, D);
- T_60_79(62, D, E, A, B, C);
- T_60_79(63, C, D, E, A, B);
- T_60_79(64, B, C, D, E, A);
- T_60_79(65, A, B, C, D, E);
- T_60_79(66, E, A, B, C, D);
- T_60_79(67, D, E, A, B, C);
- T_60_79(68, C, D, E, A, B);
- T_60_79(69, B, C, D, E, A);
- T_60_79(70, A, B, C, D, E);
- T_60_79(71, E, A, B, C, D);
- T_60_79(72, D, E, A, B, C);
- T_60_79(73, C, D, E, A, B);
- T_60_79(74, B, C, D, E, A);
- T_60_79(75, A, B, C, D, E);
- T_60_79(76, E, A, B, C, D);
- T_60_79(77, D, E, A, B, C);
- T_60_79(78, C, D, E, A, B);
- T_60_79(79, B, C, D, E, A);
-
- ctx->H[0] += A;
- ctx->H[1] += B;
- ctx->H[2] += C;
- ctx->H[3] += D;
- ctx->H[4] += E;
-}
-
-int git_hash_init(git_hash_ctx *ctx)
-{
- ctx->size = 0;
-
- /* Initialize H with the magic constants (see FIPS180 for constants) */
- ctx->H[0] = 0x67452301;
- ctx->H[1] = 0xefcdab89;
- ctx->H[2] = 0x98badcfe;
- ctx->H[3] = 0x10325476;
- ctx->H[4] = 0xc3d2e1f0;
-
- return 0;
-}
-
-int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
-{
- unsigned int lenW = ctx->size & 63;
-
- ctx->size += len;
-
- /* Read the data into W and process blocks as they get full */
- if (lenW) {
- unsigned int left = 64 - lenW;
- if (len < left)
- left = (unsigned int)len;
- memcpy(lenW + (char *)ctx->W, data, left);
- lenW = (lenW + left) & 63;
- len -= left;
- data = ((const char *)data + left);
- if (lenW)
- return 0;
- hash__block(ctx, ctx->W);
- }
- while (len >= 64) {
- hash__block(ctx, data);
- data = ((const char *)data + 64);
- len -= 64;
- }
- if (len)
- memcpy(ctx->W, data, len);
-
- return 0;
-}
-
-int git_hash_final(git_oid *out, git_hash_ctx *ctx)
-{
- static const unsigned char pad[64] = { 0x80 };
- unsigned int padlen[2];
- int i;
-
- /* Pad with a binary 1 (ie 0x80), then zeroes, then length */
- padlen[0] = htonl((uint32_t)(ctx->size >> 29));
- padlen[1] = htonl((uint32_t)(ctx->size << 3));
-
- i = ctx->size & 63;
- git_hash_update(ctx, pad, 1+ (63 & (55 - i)));
- git_hash_update(ctx, padlen, 8);
-
- /* Output hash */
- for (i = 0; i < 5; i++)
- put_be32(out->id + i*4, ctx->H[i]);
-
- return 0;
-}
-
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_hash_hash_generic_h__
-#define INCLUDE_hash_hash_generic_h__
-
-#include "common.h"
-
-#include "hash.h"
-
-struct git_hash_ctx {
- unsigned long long size;
- unsigned int H[5];
- unsigned int W[16];
-};
-
-#define git_hash_ctx_init(ctx) git_hash_init(ctx)
-#define git_hash_ctx_cleanup(ctx)
-
-GIT_INLINE(int) git_hash_global_init(void)
-{
- return 0;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "common.h"
-#include "hash.h"
-#include "hash/hash_mbedtls.h"
-
-void git_hash_ctx_cleanup(git_hash_ctx *ctx)
-{
- assert(ctx);
- mbedtls_sha1_free(&ctx->c);
-}
-
-int git_hash_init(git_hash_ctx *ctx)
-{
- assert(ctx);
- mbedtls_sha1_init(&ctx->c);
- mbedtls_sha1_starts(&ctx->c);
- return 0;
-}
-
-int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
-{
- assert(ctx);
- mbedtls_sha1_update(&ctx->c, data, len);
- return 0;
-}
-
-int git_hash_final(git_oid *out, git_hash_ctx *ctx)
-{
- assert(ctx);
- mbedtls_sha1_finish(&ctx->c, out->id);
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_hash_mbedtld_h__
-#define INCLUDE_hash_mbedtld_h__
-
-#include <mbedtls/sha1.h>
-
-struct git_hash_ctx {
- mbedtls_sha1_context c;
-};
-
-#define git_hash_ctx_init(ctx) git_hash_init(ctx)
-
-GIT_INLINE(int) git_hash_global_init(void)
-{
- return 0;
-}
-
-#endif /* INCLUDE_hash_mbedtld_h__ */
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_hash_hash_openssl_h__
-#define INCLUDE_hash_hash_openssl_h__
-
-#include "hash.h"
-
-#include <openssl/sha.h>
-
-struct git_hash_ctx {
- SHA_CTX c;
-};
-
-#define git_hash_ctx_init(ctx) git_hash_init(ctx)
-#define git_hash_ctx_cleanup(ctx)
-
-GIT_INLINE(int) git_hash_global_init(void)
-{
- return 0;
-}
-
-GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
-{
- assert(ctx);
-
- if (SHA1_Init(&ctx->c) != 1) {
- git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to initialize hash context");
- return -1;
- }
-
- return 0;
-}
-
-GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
-{
- assert(ctx);
-
- if (SHA1_Update(&ctx->c, data, len) != 1) {
- git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to update hash");
- return -1;
- }
-
- return 0;
-}
-
-GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
-{
- assert(ctx);
-
- if (SHA1_Final(out->id, &ctx->c) != 1) {
- git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to finalize hash");
- return -1;
- }
-
- return 0;
-}
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "hash_win32.h"
-
-#include "global.h"
-#include "hash.h"
-
-#include <wincrypt.h>
-#include <strsafe.h>
-
-static struct git_hash_prov hash_prov = {0};
-
-/* Hash initialization */
-
-/* Initialize CNG, if available */
-GIT_INLINE(int) hash_cng_prov_init(void)
-{
- char dll_path[MAX_PATH];
- DWORD dll_path_len, size_len;
-
- /* Only use CNG on Windows 2008 / Vista SP1 or better (Windows 6.0 SP1) */
- if (!git_has_win32_version(6, 0, 1)) {
- git_error_set(GIT_ERROR_SHA1, "CryptoNG is not supported on this platform");
- return -1;
- }
-
- /* Load bcrypt.dll explicitly from the system directory */
- if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 ||
- dll_path_len > MAX_PATH ||
- StringCchCat(dll_path, MAX_PATH, "\\") < 0 ||
- StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 ||
- (hash_prov.prov.cng.dll = LoadLibrary(dll_path)) == NULL) {
- git_error_set(GIT_ERROR_SHA1, "CryptoNG library could not be loaded");
- return -1;
- }
-
- /* Load the function addresses */
- if ((hash_prov.prov.cng.open_algorithm_provider = (hash_win32_cng_open_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptOpenAlgorithmProvider")) == NULL ||
- (hash_prov.prov.cng.get_property = (hash_win32_cng_get_property_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptGetProperty")) == NULL ||
- (hash_prov.prov.cng.create_hash = (hash_win32_cng_create_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCreateHash")) == NULL ||
- (hash_prov.prov.cng.finish_hash = (hash_win32_cng_finish_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptFinishHash")) == NULL ||
- (hash_prov.prov.cng.hash_data = (hash_win32_cng_hash_data_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptHashData")) == NULL ||
- (hash_prov.prov.cng.destroy_hash = (hash_win32_cng_destroy_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptDestroyHash")) == NULL ||
- (hash_prov.prov.cng.close_algorithm_provider = (hash_win32_cng_close_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCloseAlgorithmProvider")) == NULL) {
- FreeLibrary(hash_prov.prov.cng.dll);
-
- git_error_set(GIT_ERROR_OS, "CryptoNG functions could not be loaded");
- return -1;
- }
-
- /* Load the SHA1 algorithm */
- if (hash_prov.prov.cng.open_algorithm_provider(&hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0) {
- FreeLibrary(hash_prov.prov.cng.dll);
-
- git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized");
- return -1;
- }
-
- /* Get storage space for the hash object */
- if (hash_prov.prov.cng.get_property(hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_prov.prov.cng.hash_object_size, sizeof(DWORD), &size_len, 0) < 0) {
- hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0);
- FreeLibrary(hash_prov.prov.cng.dll);
-
- git_error_set(GIT_ERROR_OS, "algorithm handle could not be found");
- return -1;
- }
-
- hash_prov.type = CNG;
- return 0;
-}
-
-GIT_INLINE(void) hash_cng_prov_shutdown(void)
-{
- hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0);
- FreeLibrary(hash_prov.prov.cng.dll);
-
- hash_prov.type = INVALID;
-}
-
-/* Initialize CryptoAPI */
-GIT_INLINE(int) hash_cryptoapi_prov_init()
-{
- if (!CryptAcquireContext(&hash_prov.prov.cryptoapi.handle, NULL, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- git_error_set(GIT_ERROR_OS, "legacy hash context could not be started");
- return -1;
- }
-
- hash_prov.type = CRYPTOAPI;
- return 0;
-}
-
-GIT_INLINE(void) hash_cryptoapi_prov_shutdown(void)
-{
- CryptReleaseContext(hash_prov.prov.cryptoapi.handle, 0);
-
- hash_prov.type = INVALID;
-}
-
-static void git_hash_global_shutdown(void)
-{
- if (hash_prov.type == CNG)
- hash_cng_prov_shutdown();
- else if(hash_prov.type == CRYPTOAPI)
- hash_cryptoapi_prov_shutdown();
-}
-
-int git_hash_global_init(void)
-{
- int error = 0;
-
- if (hash_prov.type != INVALID)
- return 0;
-
- if ((error = hash_cng_prov_init()) < 0)
- error = hash_cryptoapi_prov_init();
-
- git__on_shutdown(git_hash_global_shutdown);
-
- return error;
-}
-
-/* CryptoAPI: available in Windows XP and newer */
-
-GIT_INLINE(int) hash_ctx_cryptoapi_init(git_hash_ctx *ctx)
-{
- ctx->type = CRYPTOAPI;
- ctx->prov = &hash_prov;
-
- return git_hash_init(ctx);
-}
-
-GIT_INLINE(int) hash_cryptoapi_init(git_hash_ctx *ctx)
-{
- if (ctx->ctx.cryptoapi.valid)
- CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle);
-
- if (!CryptCreateHash(ctx->prov->prov.cryptoapi.handle, CALG_SHA1, 0, 0, &ctx->ctx.cryptoapi.hash_handle)) {
- ctx->ctx.cryptoapi.valid = 0;
- git_error_set(GIT_ERROR_OS, "legacy hash implementation could not be created");
- return -1;
- }
-
- ctx->ctx.cryptoapi.valid = 1;
- return 0;
-}
-
-GIT_INLINE(int) hash_cryptoapi_update(git_hash_ctx *ctx, const void *_data, size_t len)
-{
- const BYTE *data = (BYTE *)_data;
-
- assert(ctx->ctx.cryptoapi.valid);
-
- while (len > 0) {
- DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len;
-
- if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, data, chunk, 0)) {
- git_error_set(GIT_ERROR_OS, "legacy hash data could not be updated");
- return -1;
- }
-
- data += chunk;
- len -= chunk;
- }
-
- return 0;
-}
-
-GIT_INLINE(int) hash_cryptoapi_final(git_oid *out, git_hash_ctx *ctx)
-{
- DWORD len = 20;
- int error = 0;
-
- assert(ctx->ctx.cryptoapi.valid);
-
- if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out->id, &len, 0)) {
- git_error_set(GIT_ERROR_OS, "legacy hash data could not be finished");
- error = -1;
- }
-
- CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle);
- ctx->ctx.cryptoapi.valid = 0;
-
- return error;
-}
-
-GIT_INLINE(void) hash_ctx_cryptoapi_cleanup(git_hash_ctx *ctx)
-{
- if (ctx->ctx.cryptoapi.valid)
- CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle);
-}
-
-/* CNG: Available in Windows Server 2008 and newer */
-
-GIT_INLINE(int) hash_ctx_cng_init(git_hash_ctx *ctx)
-{
- if ((ctx->ctx.cng.hash_object = git__malloc(hash_prov.prov.cng.hash_object_size)) == NULL)
- return -1;
-
- if (hash_prov.prov.cng.create_hash(hash_prov.prov.cng.handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_prov.prov.cng.hash_object_size, NULL, 0, 0) < 0) {
- git__free(ctx->ctx.cng.hash_object);
-
- git_error_set(GIT_ERROR_OS, "hash implementation could not be created");
- return -1;
- }
-
- ctx->type = CNG;
- ctx->prov = &hash_prov;
-
- return 0;
-}
-
-GIT_INLINE(int) hash_cng_init(git_hash_ctx *ctx)
-{
- BYTE hash[GIT_OID_RAWSZ];
-
- if (!ctx->ctx.cng.updated)
- return 0;
-
- /* CNG needs to be finished to restart */
- if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, hash, GIT_OID_RAWSZ, 0) < 0) {
- git_error_set(GIT_ERROR_OS, "hash implementation could not be finished");
- return -1;
- }
-
- ctx->ctx.cng.updated = 0;
-
- return 0;
-}
-
-GIT_INLINE(int) hash_cng_update(git_hash_ctx *ctx, const void *_data, size_t len)
-{
- PBYTE data = (PBYTE)_data;
-
- while (len > 0) {
- ULONG chunk = (len > ULONG_MAX) ? ULONG_MAX : (ULONG)len;
-
- if (ctx->prov->prov.cng.hash_data(ctx->ctx.cng.hash_handle, data, chunk, 0) < 0) {
- git_error_set(GIT_ERROR_OS, "hash could not be updated");
- return -1;
- }
-
- data += chunk;
- len -= chunk;
- }
-
- return 0;
-}
-
-GIT_INLINE(int) hash_cng_final(git_oid *out, git_hash_ctx *ctx)
-{
- if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, out->id, GIT_OID_RAWSZ, 0) < 0) {
- git_error_set(GIT_ERROR_OS, "hash could not be finished");
- return -1;
- }
-
- ctx->ctx.cng.updated = 0;
-
- return 0;
-}
-
-GIT_INLINE(void) hash_ctx_cng_cleanup(git_hash_ctx *ctx)
-{
- ctx->prov->prov.cng.destroy_hash(ctx->ctx.cng.hash_handle);
- git__free(ctx->ctx.cng.hash_object);
-}
-
-/* Indirection between CryptoAPI and CNG */
-
-int git_hash_ctx_init(git_hash_ctx *ctx)
-{
- int error = 0;
-
- assert(ctx);
-
- /*
- * When compiled with GIT_THREADS, the global hash_prov data is
- * initialized with git_libgit2_init. Otherwise, it must be initialized
- * at first use.
- */
- if (hash_prov.type == INVALID && (error = git_hash_global_init()) < 0)
- return error;
-
- memset(ctx, 0x0, sizeof(git_hash_ctx));
-
- return (hash_prov.type == CNG) ? hash_ctx_cng_init(ctx) : hash_ctx_cryptoapi_init(ctx);
-}
-
-int git_hash_init(git_hash_ctx *ctx)
-{
- assert(ctx && ctx->type);
- return (ctx->type == CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx);
-}
-
-int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
-{
- assert(ctx && ctx->type);
- return (ctx->type == CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len);
-}
-
-int git_hash_final(git_oid *out, git_hash_ctx *ctx)
-{
- assert(ctx && ctx->type);
- return (ctx->type == CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx);
-}
-
-void git_hash_ctx_cleanup(git_hash_ctx *ctx)
-{
- assert(ctx);
-
- if (ctx->type == CNG)
- hash_ctx_cng_cleanup(ctx);
- else if(ctx->type == CRYPTOAPI)
- hash_ctx_cryptoapi_cleanup(ctx);
-}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_hash_hash_win32_h__
-#define INCLUDE_hash_hash_win32_h__
-
-#include "common.h"
-
-#include "hash.h"
-
-#include <wincrypt.h>
-#include <strsafe.h>
-
-enum hash_win32_prov_type {
- INVALID = 0,
- CRYPTOAPI,
- CNG
-};
-
-/*
- * CryptoAPI is available for hashing on Windows XP and newer.
- */
-
-struct hash_cryptoapi_prov {
- HCRYPTPROV handle;
-};
-
-/*
- * CNG (bcrypt.dll) is significantly more performant than CryptoAPI and is
- * preferred, however it is only available on Windows 2008 and newer and
- * must therefore be dynamically loaded, and we must inline constants that
- * would not exist when building in pre-Windows 2008 environments.
- */
-
-#define GIT_HASH_CNG_DLL_NAME "bcrypt.dll"
-
-/* BCRYPT_SHA1_ALGORITHM */
-#define GIT_HASH_CNG_HASH_TYPE L"SHA1"
-
-/* BCRYPT_OBJECT_LENGTH */
-#define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength"
-
-/* BCRYPT_HASH_REUSEABLE_FLAGS */
-#define GIT_HASH_CNG_HASH_REUSABLE 0x00000020
-
-/* Function declarations for CNG */
-typedef NTSTATUS (WINAPI *hash_win32_cng_open_algorithm_provider_fn)(
- HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm,
- LPCWSTR pszAlgId,
- LPCWSTR pszImplementation,
- DWORD dwFlags);
-
-typedef NTSTATUS (WINAPI *hash_win32_cng_get_property_fn)(
- HANDLE /* BCRYPT_HANDLE */ hObject,
- LPCWSTR pszProperty,
- PUCHAR pbOutput,
- ULONG cbOutput,
- ULONG *pcbResult,
- ULONG dwFlags);
-
-typedef NTSTATUS (WINAPI *hash_win32_cng_create_hash_fn)(
- HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm,
- HANDLE /* BCRYPT_HASH_HANDLE */ *phHash,
- PUCHAR pbHashObject, ULONG cbHashObject,
- PUCHAR pbSecret,
- ULONG cbSecret,
- ULONG dwFlags);
-
-typedef NTSTATUS (WINAPI *hash_win32_cng_finish_hash_fn)(
- HANDLE /* BCRYPT_HASH_HANDLE */ hHash,
- PUCHAR pbOutput,
- ULONG cbOutput,
- ULONG dwFlags);
-
-typedef NTSTATUS (WINAPI *hash_win32_cng_hash_data_fn)(
- HANDLE /* BCRYPT_HASH_HANDLE */ hHash,
- PUCHAR pbInput,
- ULONG cbInput,
- ULONG dwFlags);
-
-typedef NTSTATUS (WINAPI *hash_win32_cng_destroy_hash_fn)(
- HANDLE /* BCRYPT_HASH_HANDLE */ hHash);
-
-typedef NTSTATUS (WINAPI *hash_win32_cng_close_algorithm_provider_fn)(
- HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm,
- ULONG dwFlags);
-
-struct hash_cng_prov {
- /* DLL for CNG */
- HINSTANCE dll;
-
- /* Function pointers for CNG */
- hash_win32_cng_open_algorithm_provider_fn open_algorithm_provider;
- hash_win32_cng_get_property_fn get_property;
- hash_win32_cng_create_hash_fn create_hash;
- hash_win32_cng_finish_hash_fn finish_hash;
- hash_win32_cng_hash_data_fn hash_data;
- hash_win32_cng_destroy_hash_fn destroy_hash;
- hash_win32_cng_close_algorithm_provider_fn close_algorithm_provider;
-
- HANDLE /* BCRYPT_ALG_HANDLE */ handle;
- DWORD hash_object_size;
-};
-
-struct git_hash_prov {
- enum hash_win32_prov_type type;
-
- union {
- struct hash_cryptoapi_prov cryptoapi;
- struct hash_cng_prov cng;
- } prov;
-};
-
-/* Hash contexts */
-
-struct hash_cryptoapi_ctx {
- bool valid;
- HCRYPTHASH hash_handle;
-};
-
-struct hash_cng_ctx {
- bool updated;
- HANDLE /* BCRYPT_HASH_HANDLE */ hash_handle;
- PBYTE hash_object;
-};
-
-struct git_hash_ctx {
- enum hash_win32_prov_type type;
- git_hash_prov *prov;
-
- union {
- struct hash_cryptoapi_ctx cryptoapi;
- struct hash_cng_ctx cng;
- } ctx;
-};
-
-#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_h__
+#define INCLUDE_hash_sha1_h__
+
+#include "common.h"
+
+typedef struct git_hash_sha1_ctx git_hash_sha1_ctx;
+
+#if defined(GIT_SHA1_COLLISIONDETECT)
+# include "sha1/collisiondetect.h"
+#elif defined(GIT_SHA1_COMMON_CRYPTO)
+# include "sha1/common_crypto.h"
+#elif defined(GIT_SHA1_OPENSSL)
+# include "sha1/openssl.h"
+#elif defined(GIT_SHA1_WIN32)
+# include "sha1/win32.h"
+#elif defined(GIT_SHA1_MBEDTLS)
+# include "sha1/mbedtls.h"
+#else
+# include "sha1/generic.h"
+#endif
+
+int git_hash_sha1_global_init(void);
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx);
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx);
+
+int git_hash_sha1_init(git_hash_sha1_ctx *c);
+int git_hash_sha1_update(git_hash_sha1_ctx *c, const void *data, size_t len);
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *c);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "collisiondetect.h"
+
+int git_hash_sha1_global_init(void)
+{
+ return 0;
+}
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
+{
+ return git_hash_sha1_init(ctx);
+}
+
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
+{
+ GIT_UNUSED(ctx);
+}
+
+int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ SHA1DCInit(&ctx->c);
+ return 0;
+}
+
+int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
+{
+ assert(ctx);
+ SHA1DCUpdate(&ctx->c, data, len);
+ return 0;
+}
+
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ if (SHA1DCFinal(out->id, &ctx->c)) {
+ git_error_set(GIT_ERROR_SHA1, "SHA1 collision attack detected");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_collisiondetect_h__
+#define INCLUDE_hash_sha1_collisiondetect_h__
+
+#include "hash/sha1.h"
+
+#include "sha1dc/sha1.h"
+
+struct git_hash_sha1_ctx {
+ SHA1_CTX c;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common_crypto.h"
+
+#define CC_LONG_MAX ((CC_LONG)-1)
+
+int git_hash_sha1_global_init(void)
+{
+ return 0;
+}
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
+{
+ return git_hash_sha1_init(ctx);
+}
+
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
+{
+ GIT_UNUSED(ctx);
+}
+
+int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ CC_SHA1_Init(&ctx->c);
+ return 0;
+}
+
+int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len)
+{
+ const unsigned char *data = _data;
+
+ assert(ctx);
+
+ while (len > 0) {
+ CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len;
+
+ CC_SHA1_Update(&ctx->c, data, chunk);
+
+ data += chunk;
+ len -= chunk;
+ }
+
+ return 0;
+}
+
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ CC_SHA1_Final(out->id, &ctx->c);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_common_crypto_h__
+#define INCLUDE_hash_sha1_common_crypto_h__
+
+#include "hash/sha1.h"
+
+#include <CommonCrypto/CommonDigest.h>
+
+struct git_hash_sha1_ctx {
+ CC_SHA1_CTX c;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "generic.h"
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+/*
+ * Force usage of rol or ror by selecting the one with the smaller constant.
+ * It _can_ generate slightly smaller code (a constant of 1 is special), but
+ * perhaps more importantly it's possibly faster on any uarch that does a
+ * rotate with a loop.
+ */
+
+#define SHA_ASM(op, x, n) (__extension__ ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; }))
+#define SHA_ROL(x,n) SHA_ASM("rol", x, n)
+#define SHA_ROR(x,n) SHA_ASM("ror", x, n)
+
+#else
+
+#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r)))
+#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n))
+#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n)
+
+#endif
+
+/*
+ * If you have 32 registers or more, the compiler can (and should)
+ * try to change the array[] accesses into registers. However, on
+ * machines with less than ~25 registers, that won't really work,
+ * and at least gcc will make an unholy mess of it.
+ *
+ * So to avoid that mess which just slows things down, we force
+ * the stores to memory to actually happen (we might be better off
+ * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
+ * suggested by Artur Skawina - that will also make gcc unable to
+ * try to do the silly "optimize away loads" part because it won't
+ * see what the value will be).
+ *
+ * Ben Herrenschmidt reports that on PPC, the C version comes close
+ * to the optimized asm with this (ie on PPC you don't want that
+ * 'volatile', since there are lots of registers).
+ *
+ * On ARM we get the best code generation by forcing a full memory barrier
+ * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
+ * the stack frame size simply explode and performance goes down the drain.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+ #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
+#elif defined(__GNUC__) && defined(__arm__)
+ #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
+#else
+ #define setW(x, val) (W(x) = (val))
+#endif
+
+/*
+ * Performance might be improved if the CPU architecture is OK with
+ * unaligned 32-bit loads and a fast ntohl() is available.
+ * Otherwise fall back to byte loads and shifts which is portable,
+ * and is faster on architectures with memory alignment issues.
+ */
+
+#if defined(__i386__) || defined(__x86_64__) || \
+ defined(_M_IX86) || defined(_M_X64) || \
+ defined(__ppc__) || defined(__ppc64__) || \
+ defined(__powerpc__) || defined(__powerpc64__) || \
+ defined(__s390__) || defined(__s390x__)
+
+#define get_be32(p) ntohl(*(const unsigned int *)(p))
+#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
+
+#else
+
+#define get_be32(p) ( \
+ (*((const unsigned char *)(p) + 0) << 24) | \
+ (*((const unsigned char *)(p) + 1) << 16) | \
+ (*((const unsigned char *)(p) + 2) << 8) | \
+ (*((const unsigned char *)(p) + 3) << 0) )
+#define put_be32(p, v) do { \
+ unsigned int __v = (v); \
+ *((unsigned char *)(p) + 0) = __v >> 24; \
+ *((unsigned char *)(p) + 1) = __v >> 16; \
+ *((unsigned char *)(p) + 2) = __v >> 8; \
+ *((unsigned char *)(p) + 3) = __v >> 0; } while (0)
+
+#endif
+
+/* This "rolls" over the 512-bit array */
+#define W(x) (array[(x)&15])
+
+/*
+ * Where do we get the source from? The first 16 iterations get it from
+ * the input data, the next mix it from the 512-bit array.
+ */
+#define SHA_SRC(t) get_be32(data + t)
+#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
+
+#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
+ unsigned int TEMP = input(t); setW(t, TEMP); \
+ E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \
+ B = SHA_ROR(B, 2); } while (0)
+
+#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
+#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
+#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
+
+static void hash__block(git_hash_sha1_ctx *ctx, const unsigned int *data)
+{
+ unsigned int A,B,C,D,E;
+ unsigned int array[16];
+
+ A = ctx->H[0];
+ B = ctx->H[1];
+ C = ctx->H[2];
+ D = ctx->H[3];
+ E = ctx->H[4];
+
+ /* Round 1 - iterations 0-16 take their input from 'data' */
+ T_0_15( 0, A, B, C, D, E);
+ T_0_15( 1, E, A, B, C, D);
+ T_0_15( 2, D, E, A, B, C);
+ T_0_15( 3, C, D, E, A, B);
+ T_0_15( 4, B, C, D, E, A);
+ T_0_15( 5, A, B, C, D, E);
+ T_0_15( 6, E, A, B, C, D);
+ T_0_15( 7, D, E, A, B, C);
+ T_0_15( 8, C, D, E, A, B);
+ T_0_15( 9, B, C, D, E, A);
+ T_0_15(10, A, B, C, D, E);
+ T_0_15(11, E, A, B, C, D);
+ T_0_15(12, D, E, A, B, C);
+ T_0_15(13, C, D, E, A, B);
+ T_0_15(14, B, C, D, E, A);
+ T_0_15(15, A, B, C, D, E);
+
+ /* Round 1 - tail. Input from 512-bit mixing array */
+ T_16_19(16, E, A, B, C, D);
+ T_16_19(17, D, E, A, B, C);
+ T_16_19(18, C, D, E, A, B);
+ T_16_19(19, B, C, D, E, A);
+
+ /* Round 2 */
+ T_20_39(20, A, B, C, D, E);
+ T_20_39(21, E, A, B, C, D);
+ T_20_39(22, D, E, A, B, C);
+ T_20_39(23, C, D, E, A, B);
+ T_20_39(24, B, C, D, E, A);
+ T_20_39(25, A, B, C, D, E);
+ T_20_39(26, E, A, B, C, D);
+ T_20_39(27, D, E, A, B, C);
+ T_20_39(28, C, D, E, A, B);
+ T_20_39(29, B, C, D, E, A);
+ T_20_39(30, A, B, C, D, E);
+ T_20_39(31, E, A, B, C, D);
+ T_20_39(32, D, E, A, B, C);
+ T_20_39(33, C, D, E, A, B);
+ T_20_39(34, B, C, D, E, A);
+ T_20_39(35, A, B, C, D, E);
+ T_20_39(36, E, A, B, C, D);
+ T_20_39(37, D, E, A, B, C);
+ T_20_39(38, C, D, E, A, B);
+ T_20_39(39, B, C, D, E, A);
+
+ /* Round 3 */
+ T_40_59(40, A, B, C, D, E);
+ T_40_59(41, E, A, B, C, D);
+ T_40_59(42, D, E, A, B, C);
+ T_40_59(43, C, D, E, A, B);
+ T_40_59(44, B, C, D, E, A);
+ T_40_59(45, A, B, C, D, E);
+ T_40_59(46, E, A, B, C, D);
+ T_40_59(47, D, E, A, B, C);
+ T_40_59(48, C, D, E, A, B);
+ T_40_59(49, B, C, D, E, A);
+ T_40_59(50, A, B, C, D, E);
+ T_40_59(51, E, A, B, C, D);
+ T_40_59(52, D, E, A, B, C);
+ T_40_59(53, C, D, E, A, B);
+ T_40_59(54, B, C, D, E, A);
+ T_40_59(55, A, B, C, D, E);
+ T_40_59(56, E, A, B, C, D);
+ T_40_59(57, D, E, A, B, C);
+ T_40_59(58, C, D, E, A, B);
+ T_40_59(59, B, C, D, E, A);
+
+ /* Round 4 */
+ T_60_79(60, A, B, C, D, E);
+ T_60_79(61, E, A, B, C, D);
+ T_60_79(62, D, E, A, B, C);
+ T_60_79(63, C, D, E, A, B);
+ T_60_79(64, B, C, D, E, A);
+ T_60_79(65, A, B, C, D, E);
+ T_60_79(66, E, A, B, C, D);
+ T_60_79(67, D, E, A, B, C);
+ T_60_79(68, C, D, E, A, B);
+ T_60_79(69, B, C, D, E, A);
+ T_60_79(70, A, B, C, D, E);
+ T_60_79(71, E, A, B, C, D);
+ T_60_79(72, D, E, A, B, C);
+ T_60_79(73, C, D, E, A, B);
+ T_60_79(74, B, C, D, E, A);
+ T_60_79(75, A, B, C, D, E);
+ T_60_79(76, E, A, B, C, D);
+ T_60_79(77, D, E, A, B, C);
+ T_60_79(78, C, D, E, A, B);
+ T_60_79(79, B, C, D, E, A);
+
+ ctx->H[0] += A;
+ ctx->H[1] += B;
+ ctx->H[2] += C;
+ ctx->H[3] += D;
+ ctx->H[4] += E;
+}
+
+int git_hash_sha1_global_init(void)
+{
+ return 0;
+}
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
+{
+ return git_hash_sha1_init(ctx);
+}
+
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
+{
+ GIT_UNUSED(ctx);
+}
+
+int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
+{
+ ctx->size = 0;
+
+ /* Initialize H with the magic constants (see FIPS180 for constants) */
+ ctx->H[0] = 0x67452301;
+ ctx->H[1] = 0xefcdab89;
+ ctx->H[2] = 0x98badcfe;
+ ctx->H[3] = 0x10325476;
+ ctx->H[4] = 0xc3d2e1f0;
+
+ return 0;
+}
+
+int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
+{
+ unsigned int lenW = ctx->size & 63;
+
+ ctx->size += len;
+
+ /* Read the data into W and process blocks as they get full */
+ if (lenW) {
+ unsigned int left = 64 - lenW;
+ if (len < left)
+ left = (unsigned int)len;
+ memcpy(lenW + (char *)ctx->W, data, left);
+ lenW = (lenW + left) & 63;
+ len -= left;
+ data = ((const char *)data + left);
+ if (lenW)
+ return 0;
+ hash__block(ctx, ctx->W);
+ }
+ while (len >= 64) {
+ hash__block(ctx, data);
+ data = ((const char *)data + 64);
+ len -= 64;
+ }
+ if (len)
+ memcpy(ctx->W, data, len);
+
+ return 0;
+}
+
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ static const unsigned char pad[64] = { 0x80 };
+ unsigned int padlen[2];
+ int i;
+
+ /* Pad with a binary 1 (ie 0x80), then zeroes, then length */
+ padlen[0] = htonl((uint32_t)(ctx->size >> 29));
+ padlen[1] = htonl((uint32_t)(ctx->size << 3));
+
+ i = ctx->size & 63;
+ git_hash_sha1_update(ctx, pad, 1+ (63 & (55 - i)));
+ git_hash_sha1_update(ctx, padlen, 8);
+
+ /* Output hash */
+ for (i = 0; i < 5; i++)
+ put_be32(out->id + i*4, ctx->H[i]);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_generic_h__
+#define INCLUDE_hash_sha1_generic_h__
+
+#include "hash/sha1.h"
+
+struct git_hash_sha1_ctx {
+ unsigned long long size;
+ unsigned int H[5];
+ unsigned int W[16];
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "mbedtls.h"
+
+int git_hash_sha1_global_init(void)
+{
+ return 0;
+}
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
+{
+ return git_hash_sha1_init(ctx);
+}
+
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ mbedtls_sha1_free(&ctx->c);
+}
+
+int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ mbedtls_sha1_init(&ctx->c);
+ mbedtls_sha1_starts(&ctx->c);
+ return 0;
+}
+
+int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
+{
+ assert(ctx);
+ mbedtls_sha1_update(&ctx->c, data, len);
+ return 0;
+}
+
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+ mbedtls_sha1_finish(&ctx->c, out->id);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_mbedtls_h__
+#define INCLUDE_hash_sha1_mbedtls_h__
+
+#include "hash/sha1.h"
+
+#include <mbedtls/sha1.h>
+
+struct git_hash_sha1_ctx {
+ mbedtls_sha1_context c;
+};
+
+#endif /* INCLUDE_hash_sha1_mbedtls_h__ */
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "openssl.h"
+
+int git_hash_sha1_global_init(void)
+{
+ return 0;
+}
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
+{
+ return git_hash_sha1_init(ctx);
+}
+
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
+{
+ GIT_UNUSED(ctx);
+}
+
+int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+
+ if (SHA1_Init(&ctx->c) != 1) {
+ git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to initialize hash context");
+ return -1;
+ }
+
+ return 0;
+}
+
+int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
+{
+ assert(ctx);
+
+ if (SHA1_Update(&ctx->c, data, len) != 1) {
+ git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to update hash");
+ return -1;
+ }
+
+ return 0;
+}
+
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+
+ if (SHA1_Final(out->id, &ctx->c) != 1) {
+ git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to finalize hash");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_openssl_h__
+#define INCLUDE_hash_sha1_openssl_h__
+
+#include "hash/sha1.h"
+
+#include <openssl/sha.h>
+
+struct git_hash_sha1_ctx {
+ SHA_CTX c;
+};
+
+#endif
--- /dev/null
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow (danshu@microsoft.com)
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <string.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __unix__
+#include <sys/types.h> /* make sure macros like _BIG_ENDIAN visible */
+#endif
+#endif
+
+#ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C
+#include SHA1DC_CUSTOM_INCLUDE_SHA1_C
+#endif
+
+#ifndef SHA1DC_INIT_SAFE_HASH_DEFAULT
+#define SHA1DC_INIT_SAFE_HASH_DEFAULT 1
+#endif
+
+#include "sha1.h"
+#include "ubc_check.h"
+
+#if (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
+ defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || \
+ defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || \
+ defined(__386) || defined(_M_X64) || defined(_M_AMD64))
+#define SHA1DC_ON_INTEL_LIKE_PROCESSOR
+#endif
+
+/*
+ Because Little-Endian architectures are most common,
+ we only set SHA1DC_BIGENDIAN if one of these conditions is met.
+ Note that all MSFT platforms are little endian,
+ so none of these will be defined under the MSC compiler.
+ If you are compiling on a big endian platform and your compiler does not define one of these,
+ you will have to add whatever macros your tool chain defines to indicate Big-Endianness.
+ */
+
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
+/*
+ * Should detect Big Endian under GCC since at least 4.6.0 (gcc svn
+ * rev #165881). See
+ * https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
+ *
+ * This also works under clang since 3.2, it copied the GCC-ism. See
+ * clang.git's 3b198a97d2 ("Preprocessor: add __BYTE_ORDER__
+ * predefined macro", 2012-07-27)
+ */
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define SHA1DC_BIGENDIAN
+#endif
+
+/* Not under GCC-alike */
+#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN)
+/*
+ * Should detect Big Endian under glibc.git since 14245eb70e ("entered
+ * into RCS", 1992-11-25). Defined in <endian.h> which will have been
+ * brought in by standard headers. See glibc.git and
+ * https://sourceforge.net/p/predef/wiki/Endianness/
+ */
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define SHA1DC_BIGENDIAN
+#endif
+
+/* Not under GCC-alike or glibc */
+#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
+/*
+ * *BSD and newlib (embeded linux, cygwin, etc).
+ * the defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) part prevents
+ * this condition from matching with Solaris/sparc.
+ * (Solaris defines only one endian macro)
+ */
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define SHA1DC_BIGENDIAN
+#endif
+
+/* Not under GCC-alike or glibc or *BSD or newlib */
+#elif (defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
+ defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || \
+ defined(__sparc))
+/*
+ * Should define Big Endian for a whitelist of known processors. See
+ * https://sourceforge.net/p/predef/wiki/Endianness/ and
+ * http://www.oracle.com/technetwork/server-storage/solaris/portingtosolaris-138514.html
+ */
+#define SHA1DC_BIGENDIAN
+
+/* Not under GCC-alike or glibc or *BSD or newlib or <processor whitelist> */
+#elif (defined(_AIX) || defined(__hpux))
+
+/*
+ * Defines Big Endian on a whitelist of OSs that are known to be Big
+ * Endian-only. See
+ * https://public-inbox.org/git/93056823-2740-d072-1ebd-46b440b33d7e@felt.demon.nl/
+ */
+#define SHA1DC_BIGENDIAN
+
+/* Not under GCC-alike or glibc or *BSD or newlib or <processor whitelist> or <os whitelist> */
+#elif defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR)
+/*
+ * As a last resort before we do anything else we're not 100% sure
+ * about below, we blacklist specific processors here. We could add
+ * more, see e.g. https://wiki.debian.org/ArchitectureSpecificsMemo
+ */
+#else /* Not under GCC-alike or glibc or *BSD or newlib or <processor whitelist> or <os whitelist> or <processor blacklist> */
+
+/* We do nothing more here for now */
+/*#error "Uncomment this to see if you fall through all the detection"*/
+
+#endif /* Big Endian detection */
+
+#if (defined(SHA1DC_FORCE_LITTLEENDIAN) && defined(SHA1DC_BIGENDIAN))
+#undef SHA1DC_BIGENDIAN
+#endif
+#if (defined(SHA1DC_FORCE_BIGENDIAN) && !defined(SHA1DC_BIGENDIAN))
+#define SHA1DC_BIGENDIAN
+#endif
+/*ENDIANNESS SELECTION*/
+
+#ifndef SHA1DC_FORCE_ALIGNED_ACCESS
+#if defined(SHA1DC_FORCE_UNALIGNED_ACCESS) || defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR)
+#define SHA1DC_ALLOW_UNALIGNED_ACCESS
+#endif /*UNALIGNED ACCESS DETECTION*/
+#endif /*FORCE ALIGNED ACCESS*/
+
+#define rotate_right(x,n) (((x)>>(n))|((x)<<(32-(n))))
+#define rotate_left(x,n) (((x)<<(n))|((x)>>(32-(n))))
+
+#define sha1_bswap32(x) \
+ {x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF); x = (x << 16) | (x >> 16);}
+
+#define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1))
+
+#ifdef SHA1DC_BIGENDIAN
+ #define sha1_load(m, t, temp) { temp = m[t]; }
+#else
+ #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); }
+#endif
+
+#define sha1_store(W, t, x) *(volatile uint32_t *)&W[t] = x
+
+#define sha1_f1(b,c,d) ((d)^((b)&((c)^(d))))
+#define sha1_f2(b,c,d) ((b)^(c)^(d))
+#define sha1_f3(b,c,d) (((b)&(c))+((d)&((b)^(c))))
+#define sha1_f4(b,c,d) ((b)^(c)^(d))
+
+#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; b = rotate_left(b, 30); }
+#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; b = rotate_left(b, 30); }
+#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; b = rotate_left(b, 30); }
+#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, m, t) \
+ { e += rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; b = rotate_left(b, 30); }
+
+#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; }
+#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; }
+#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; }
+#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, m, t) \
+ { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; }
+
+#define SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, t, temp) \
+ {sha1_load(m, t, temp); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30);}
+
+#define SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30); }
+
+#define SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1; b = rotate_left(b, 30); }
+
+#define SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC; b = rotate_left(b, 30); }
+
+#define SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, t, temp) \
+ {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6; b = rotate_left(b, 30); }
+
+
+#define SHA1_STORE_STATE(i) states[i][0] = a; states[i][1] = b; states[i][2] = c; states[i][3] = d; states[i][4] = e;
+
+#ifdef BUILDNOCOLLDETECTSHA1COMPRESSION
+void sha1_compression(uint32_t ihv[5], const uint32_t m[16])
+{
+ uint32_t W[80];
+ uint32_t a,b,c,d,e;
+ unsigned i;
+
+ memcpy(W, m, 16 * 4);
+ for (i = 16; i < 80; ++i)
+ W[i] = sha1_mix(W, i);
+
+ a = ihv[0]; b = ihv[1]; c = ihv[2]; d = ihv[3]; e = ihv[4];
+
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19);
+
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39);
+
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59);
+
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79);
+
+ ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
+}
+#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/
+
+
+static void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80])
+{
+ uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4];
+
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18);
+ HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19);
+
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38);
+ HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39);
+
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58);
+ HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59);
+
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78);
+ HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79);
+
+ ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
+}
+
+
+
+void sha1_compression_states(uint32_t ihv[5], const uint32_t m[16], uint32_t W[80], uint32_t states[80][5])
+{
+ uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4];
+ uint32_t temp;
+
+#ifdef DOSTORESTATE00
+ SHA1_STORE_STATE(0)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp);
+
+#ifdef DOSTORESTATE01
+ SHA1_STORE_STATE(1)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp);
+
+#ifdef DOSTORESTATE02
+ SHA1_STORE_STATE(2)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp);
+
+#ifdef DOSTORESTATE03
+ SHA1_STORE_STATE(3)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp);
+
+#ifdef DOSTORESTATE04
+ SHA1_STORE_STATE(4)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp);
+
+#ifdef DOSTORESTATE05
+ SHA1_STORE_STATE(5)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp);
+
+#ifdef DOSTORESTATE06
+ SHA1_STORE_STATE(6)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp);
+
+#ifdef DOSTORESTATE07
+ SHA1_STORE_STATE(7)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp);
+
+#ifdef DOSTORESTATE08
+ SHA1_STORE_STATE(8)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp);
+
+#ifdef DOSTORESTATE09
+ SHA1_STORE_STATE(9)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp);
+
+#ifdef DOSTORESTATE10
+ SHA1_STORE_STATE(10)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp);
+
+#ifdef DOSTORESTATE11
+ SHA1_STORE_STATE(11)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp);
+
+#ifdef DOSTORESTATE12
+ SHA1_STORE_STATE(12)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp);
+
+#ifdef DOSTORESTATE13
+ SHA1_STORE_STATE(13)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp);
+
+#ifdef DOSTORESTATE14
+ SHA1_STORE_STATE(14)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp);
+
+#ifdef DOSTORESTATE15
+ SHA1_STORE_STATE(15)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp);
+
+#ifdef DOSTORESTATE16
+ SHA1_STORE_STATE(16)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp);
+
+#ifdef DOSTORESTATE17
+ SHA1_STORE_STATE(17)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp);
+
+#ifdef DOSTORESTATE18
+ SHA1_STORE_STATE(18)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp);
+
+#ifdef DOSTORESTATE19
+ SHA1_STORE_STATE(19)
+#endif
+ SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp);
+
+
+
+#ifdef DOSTORESTATE20
+ SHA1_STORE_STATE(20)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp);
+
+#ifdef DOSTORESTATE21
+ SHA1_STORE_STATE(21)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp);
+
+#ifdef DOSTORESTATE22
+ SHA1_STORE_STATE(22)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp);
+
+#ifdef DOSTORESTATE23
+ SHA1_STORE_STATE(23)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp);
+
+#ifdef DOSTORESTATE24
+ SHA1_STORE_STATE(24)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp);
+
+#ifdef DOSTORESTATE25
+ SHA1_STORE_STATE(25)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp);
+
+#ifdef DOSTORESTATE26
+ SHA1_STORE_STATE(26)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp);
+
+#ifdef DOSTORESTATE27
+ SHA1_STORE_STATE(27)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp);
+
+#ifdef DOSTORESTATE28
+ SHA1_STORE_STATE(28)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp);
+
+#ifdef DOSTORESTATE29
+ SHA1_STORE_STATE(29)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp);
+
+#ifdef DOSTORESTATE30
+ SHA1_STORE_STATE(30)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp);
+
+#ifdef DOSTORESTATE31
+ SHA1_STORE_STATE(31)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp);
+
+#ifdef DOSTORESTATE32
+ SHA1_STORE_STATE(32)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp);
+
+#ifdef DOSTORESTATE33
+ SHA1_STORE_STATE(33)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp);
+
+#ifdef DOSTORESTATE34
+ SHA1_STORE_STATE(34)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp);
+
+#ifdef DOSTORESTATE35
+ SHA1_STORE_STATE(35)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp);
+
+#ifdef DOSTORESTATE36
+ SHA1_STORE_STATE(36)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp);
+
+#ifdef DOSTORESTATE37
+ SHA1_STORE_STATE(37)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp);
+
+#ifdef DOSTORESTATE38
+ SHA1_STORE_STATE(38)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp);
+
+#ifdef DOSTORESTATE39
+ SHA1_STORE_STATE(39)
+#endif
+ SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp);
+
+
+
+#ifdef DOSTORESTATE40
+ SHA1_STORE_STATE(40)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp);
+
+#ifdef DOSTORESTATE41
+ SHA1_STORE_STATE(41)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp);
+
+#ifdef DOSTORESTATE42
+ SHA1_STORE_STATE(42)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp);
+
+#ifdef DOSTORESTATE43
+ SHA1_STORE_STATE(43)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp);
+
+#ifdef DOSTORESTATE44
+ SHA1_STORE_STATE(44)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp);
+
+#ifdef DOSTORESTATE45
+ SHA1_STORE_STATE(45)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp);
+
+#ifdef DOSTORESTATE46
+ SHA1_STORE_STATE(46)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp);
+
+#ifdef DOSTORESTATE47
+ SHA1_STORE_STATE(47)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp);
+
+#ifdef DOSTORESTATE48
+ SHA1_STORE_STATE(48)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp);
+
+#ifdef DOSTORESTATE49
+ SHA1_STORE_STATE(49)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp);
+
+#ifdef DOSTORESTATE50
+ SHA1_STORE_STATE(50)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp);
+
+#ifdef DOSTORESTATE51
+ SHA1_STORE_STATE(51)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp);
+
+#ifdef DOSTORESTATE52
+ SHA1_STORE_STATE(52)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp);
+
+#ifdef DOSTORESTATE53
+ SHA1_STORE_STATE(53)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp);
+
+#ifdef DOSTORESTATE54
+ SHA1_STORE_STATE(54)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp);
+
+#ifdef DOSTORESTATE55
+ SHA1_STORE_STATE(55)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp);
+
+#ifdef DOSTORESTATE56
+ SHA1_STORE_STATE(56)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp);
+
+#ifdef DOSTORESTATE57
+ SHA1_STORE_STATE(57)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp);
+
+#ifdef DOSTORESTATE58
+ SHA1_STORE_STATE(58)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp);
+
+#ifdef DOSTORESTATE59
+ SHA1_STORE_STATE(59)
+#endif
+ SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp);
+
+
+
+
+#ifdef DOSTORESTATE60
+ SHA1_STORE_STATE(60)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp);
+
+#ifdef DOSTORESTATE61
+ SHA1_STORE_STATE(61)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp);
+
+#ifdef DOSTORESTATE62
+ SHA1_STORE_STATE(62)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp);
+
+#ifdef DOSTORESTATE63
+ SHA1_STORE_STATE(63)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp);
+
+#ifdef DOSTORESTATE64
+ SHA1_STORE_STATE(64)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp);
+
+#ifdef DOSTORESTATE65
+ SHA1_STORE_STATE(65)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp);
+
+#ifdef DOSTORESTATE66
+ SHA1_STORE_STATE(66)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp);
+
+#ifdef DOSTORESTATE67
+ SHA1_STORE_STATE(67)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp);
+
+#ifdef DOSTORESTATE68
+ SHA1_STORE_STATE(68)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp);
+
+#ifdef DOSTORESTATE69
+ SHA1_STORE_STATE(69)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp);
+
+#ifdef DOSTORESTATE70
+ SHA1_STORE_STATE(70)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp);
+
+#ifdef DOSTORESTATE71
+ SHA1_STORE_STATE(71)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp);
+
+#ifdef DOSTORESTATE72
+ SHA1_STORE_STATE(72)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp);
+
+#ifdef DOSTORESTATE73
+ SHA1_STORE_STATE(73)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp);
+
+#ifdef DOSTORESTATE74
+ SHA1_STORE_STATE(74)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp);
+
+#ifdef DOSTORESTATE75
+ SHA1_STORE_STATE(75)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp);
+
+#ifdef DOSTORESTATE76
+ SHA1_STORE_STATE(76)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp);
+
+#ifdef DOSTORESTATE77
+ SHA1_STORE_STATE(77)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp);
+
+#ifdef DOSTORESTATE78
+ SHA1_STORE_STATE(78)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp);
+
+#ifdef DOSTORESTATE79
+ SHA1_STORE_STATE(79)
+#endif
+ SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp);
+
+
+
+ ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
+}
+
+
+
+
+#define SHA1_RECOMPRESS(t) \
+static void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \
+{ \
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; \
+ if (t > 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 79); \
+ if (t > 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 78); \
+ if (t > 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 77); \
+ if (t > 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 76); \
+ if (t > 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 75); \
+ if (t > 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 74); \
+ if (t > 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 73); \
+ if (t > 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 72); \
+ if (t > 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 71); \
+ if (t > 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 70); \
+ if (t > 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 69); \
+ if (t > 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 68); \
+ if (t > 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 67); \
+ if (t > 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 66); \
+ if (t > 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 65); \
+ if (t > 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 64); \
+ if (t > 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 63); \
+ if (t > 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 62); \
+ if (t > 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 61); \
+ if (t > 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 60); \
+ if (t > 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 59); \
+ if (t > 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 58); \
+ if (t > 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 57); \
+ if (t > 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 56); \
+ if (t > 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 55); \
+ if (t > 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 54); \
+ if (t > 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 53); \
+ if (t > 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 52); \
+ if (t > 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 51); \
+ if (t > 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 50); \
+ if (t > 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 49); \
+ if (t > 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 48); \
+ if (t > 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 47); \
+ if (t > 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 46); \
+ if (t > 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 45); \
+ if (t > 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 44); \
+ if (t > 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 43); \
+ if (t > 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 42); \
+ if (t > 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 41); \
+ if (t > 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 40); \
+ if (t > 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 39); \
+ if (t > 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 38); \
+ if (t > 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 37); \
+ if (t > 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 36); \
+ if (t > 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 35); \
+ if (t > 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 34); \
+ if (t > 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 33); \
+ if (t > 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 32); \
+ if (t > 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 31); \
+ if (t > 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 30); \
+ if (t > 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 29); \
+ if (t > 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 28); \
+ if (t > 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 27); \
+ if (t > 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 26); \
+ if (t > 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 25); \
+ if (t > 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 24); \
+ if (t > 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 23); \
+ if (t > 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 22); \
+ if (t > 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 21); \
+ if (t > 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 20); \
+ if (t > 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 19); \
+ if (t > 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 18); \
+ if (t > 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 17); \
+ if (t > 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 16); \
+ if (t > 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 15); \
+ if (t > 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 14); \
+ if (t > 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 13); \
+ if (t > 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 12); \
+ if (t > 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 11); \
+ if (t > 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 10); \
+ if (t > 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 9); \
+ if (t > 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 8); \
+ if (t > 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 7); \
+ if (t > 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 6); \
+ if (t > 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 5); \
+ if (t > 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 4); \
+ if (t > 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 3); \
+ if (t > 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 2); \
+ if (t > 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 1); \
+ if (t > 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 0); \
+ ihvin[0] = a; ihvin[1] = b; ihvin[2] = c; ihvin[3] = d; ihvin[4] = e; \
+ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; \
+ if (t <= 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 0); \
+ if (t <= 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 1); \
+ if (t <= 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 2); \
+ if (t <= 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 3); \
+ if (t <= 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 4); \
+ if (t <= 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 5); \
+ if (t <= 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 6); \
+ if (t <= 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 7); \
+ if (t <= 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 8); \
+ if (t <= 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 9); \
+ if (t <= 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 10); \
+ if (t <= 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 11); \
+ if (t <= 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 12); \
+ if (t <= 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 13); \
+ if (t <= 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 14); \
+ if (t <= 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 15); \
+ if (t <= 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 16); \
+ if (t <= 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 17); \
+ if (t <= 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 18); \
+ if (t <= 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 19); \
+ if (t <= 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 20); \
+ if (t <= 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 21); \
+ if (t <= 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 22); \
+ if (t <= 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 23); \
+ if (t <= 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 24); \
+ if (t <= 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 25); \
+ if (t <= 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 26); \
+ if (t <= 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 27); \
+ if (t <= 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 28); \
+ if (t <= 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 29); \
+ if (t <= 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 30); \
+ if (t <= 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 31); \
+ if (t <= 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 32); \
+ if (t <= 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 33); \
+ if (t <= 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 34); \
+ if (t <= 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 35); \
+ if (t <= 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 36); \
+ if (t <= 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 37); \
+ if (t <= 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 38); \
+ if (t <= 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 39); \
+ if (t <= 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 40); \
+ if (t <= 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 41); \
+ if (t <= 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 42); \
+ if (t <= 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 43); \
+ if (t <= 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 44); \
+ if (t <= 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 45); \
+ if (t <= 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 46); \
+ if (t <= 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 47); \
+ if (t <= 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 48); \
+ if (t <= 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 49); \
+ if (t <= 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 50); \
+ if (t <= 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 51); \
+ if (t <= 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 52); \
+ if (t <= 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 53); \
+ if (t <= 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 54); \
+ if (t <= 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 55); \
+ if (t <= 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 56); \
+ if (t <= 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 57); \
+ if (t <= 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 58); \
+ if (t <= 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 59); \
+ if (t <= 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 60); \
+ if (t <= 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 61); \
+ if (t <= 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 62); \
+ if (t <= 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 63); \
+ if (t <= 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 64); \
+ if (t <= 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 65); \
+ if (t <= 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 66); \
+ if (t <= 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 67); \
+ if (t <= 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 68); \
+ if (t <= 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 69); \
+ if (t <= 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 70); \
+ if (t <= 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 71); \
+ if (t <= 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 72); \
+ if (t <= 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 73); \
+ if (t <= 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 74); \
+ if (t <= 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 75); \
+ if (t <= 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 76); \
+ if (t <= 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 77); \
+ if (t <= 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 78); \
+ if (t <= 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 79); \
+ ihvout[0] = ihvin[0] + a; ihvout[1] = ihvin[1] + b; ihvout[2] = ihvin[2] + c; ihvout[3] = ihvin[3] + d; ihvout[4] = ihvin[4] + e; \
+}
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4127) /* Compiler complains about the checks in the above macro being constant. */
+#endif
+
+#ifdef DOSTORESTATE0
+SHA1_RECOMPRESS(0)
+#endif
+
+#ifdef DOSTORESTATE1
+SHA1_RECOMPRESS(1)
+#endif
+
+#ifdef DOSTORESTATE2
+SHA1_RECOMPRESS(2)
+#endif
+
+#ifdef DOSTORESTATE3
+SHA1_RECOMPRESS(3)
+#endif
+
+#ifdef DOSTORESTATE4
+SHA1_RECOMPRESS(4)
+#endif
+
+#ifdef DOSTORESTATE5
+SHA1_RECOMPRESS(5)
+#endif
+
+#ifdef DOSTORESTATE6
+SHA1_RECOMPRESS(6)
+#endif
+
+#ifdef DOSTORESTATE7
+SHA1_RECOMPRESS(7)
+#endif
+
+#ifdef DOSTORESTATE8
+SHA1_RECOMPRESS(8)
+#endif
+
+#ifdef DOSTORESTATE9
+SHA1_RECOMPRESS(9)
+#endif
+
+#ifdef DOSTORESTATE10
+SHA1_RECOMPRESS(10)
+#endif
+
+#ifdef DOSTORESTATE11
+SHA1_RECOMPRESS(11)
+#endif
+
+#ifdef DOSTORESTATE12
+SHA1_RECOMPRESS(12)
+#endif
+
+#ifdef DOSTORESTATE13
+SHA1_RECOMPRESS(13)
+#endif
+
+#ifdef DOSTORESTATE14
+SHA1_RECOMPRESS(14)
+#endif
+
+#ifdef DOSTORESTATE15
+SHA1_RECOMPRESS(15)
+#endif
+
+#ifdef DOSTORESTATE16
+SHA1_RECOMPRESS(16)
+#endif
+
+#ifdef DOSTORESTATE17
+SHA1_RECOMPRESS(17)
+#endif
+
+#ifdef DOSTORESTATE18
+SHA1_RECOMPRESS(18)
+#endif
+
+#ifdef DOSTORESTATE19
+SHA1_RECOMPRESS(19)
+#endif
+
+#ifdef DOSTORESTATE20
+SHA1_RECOMPRESS(20)
+#endif
+
+#ifdef DOSTORESTATE21
+SHA1_RECOMPRESS(21)
+#endif
+
+#ifdef DOSTORESTATE22
+SHA1_RECOMPRESS(22)
+#endif
+
+#ifdef DOSTORESTATE23
+SHA1_RECOMPRESS(23)
+#endif
+
+#ifdef DOSTORESTATE24
+SHA1_RECOMPRESS(24)
+#endif
+
+#ifdef DOSTORESTATE25
+SHA1_RECOMPRESS(25)
+#endif
+
+#ifdef DOSTORESTATE26
+SHA1_RECOMPRESS(26)
+#endif
+
+#ifdef DOSTORESTATE27
+SHA1_RECOMPRESS(27)
+#endif
+
+#ifdef DOSTORESTATE28
+SHA1_RECOMPRESS(28)
+#endif
+
+#ifdef DOSTORESTATE29
+SHA1_RECOMPRESS(29)
+#endif
+
+#ifdef DOSTORESTATE30
+SHA1_RECOMPRESS(30)
+#endif
+
+#ifdef DOSTORESTATE31
+SHA1_RECOMPRESS(31)
+#endif
+
+#ifdef DOSTORESTATE32
+SHA1_RECOMPRESS(32)
+#endif
+
+#ifdef DOSTORESTATE33
+SHA1_RECOMPRESS(33)
+#endif
+
+#ifdef DOSTORESTATE34
+SHA1_RECOMPRESS(34)
+#endif
+
+#ifdef DOSTORESTATE35
+SHA1_RECOMPRESS(35)
+#endif
+
+#ifdef DOSTORESTATE36
+SHA1_RECOMPRESS(36)
+#endif
+
+#ifdef DOSTORESTATE37
+SHA1_RECOMPRESS(37)
+#endif
+
+#ifdef DOSTORESTATE38
+SHA1_RECOMPRESS(38)
+#endif
+
+#ifdef DOSTORESTATE39
+SHA1_RECOMPRESS(39)
+#endif
+
+#ifdef DOSTORESTATE40
+SHA1_RECOMPRESS(40)
+#endif
+
+#ifdef DOSTORESTATE41
+SHA1_RECOMPRESS(41)
+#endif
+
+#ifdef DOSTORESTATE42
+SHA1_RECOMPRESS(42)
+#endif
+
+#ifdef DOSTORESTATE43
+SHA1_RECOMPRESS(43)
+#endif
+
+#ifdef DOSTORESTATE44
+SHA1_RECOMPRESS(44)
+#endif
+
+#ifdef DOSTORESTATE45
+SHA1_RECOMPRESS(45)
+#endif
+
+#ifdef DOSTORESTATE46
+SHA1_RECOMPRESS(46)
+#endif
+
+#ifdef DOSTORESTATE47
+SHA1_RECOMPRESS(47)
+#endif
+
+#ifdef DOSTORESTATE48
+SHA1_RECOMPRESS(48)
+#endif
+
+#ifdef DOSTORESTATE49
+SHA1_RECOMPRESS(49)
+#endif
+
+#ifdef DOSTORESTATE50
+SHA1_RECOMPRESS(50)
+#endif
+
+#ifdef DOSTORESTATE51
+SHA1_RECOMPRESS(51)
+#endif
+
+#ifdef DOSTORESTATE52
+SHA1_RECOMPRESS(52)
+#endif
+
+#ifdef DOSTORESTATE53
+SHA1_RECOMPRESS(53)
+#endif
+
+#ifdef DOSTORESTATE54
+SHA1_RECOMPRESS(54)
+#endif
+
+#ifdef DOSTORESTATE55
+SHA1_RECOMPRESS(55)
+#endif
+
+#ifdef DOSTORESTATE56
+SHA1_RECOMPRESS(56)
+#endif
+
+#ifdef DOSTORESTATE57
+SHA1_RECOMPRESS(57)
+#endif
+
+#ifdef DOSTORESTATE58
+SHA1_RECOMPRESS(58)
+#endif
+
+#ifdef DOSTORESTATE59
+SHA1_RECOMPRESS(59)
+#endif
+
+#ifdef DOSTORESTATE60
+SHA1_RECOMPRESS(60)
+#endif
+
+#ifdef DOSTORESTATE61
+SHA1_RECOMPRESS(61)
+#endif
+
+#ifdef DOSTORESTATE62
+SHA1_RECOMPRESS(62)
+#endif
+
+#ifdef DOSTORESTATE63
+SHA1_RECOMPRESS(63)
+#endif
+
+#ifdef DOSTORESTATE64
+SHA1_RECOMPRESS(64)
+#endif
+
+#ifdef DOSTORESTATE65
+SHA1_RECOMPRESS(65)
+#endif
+
+#ifdef DOSTORESTATE66
+SHA1_RECOMPRESS(66)
+#endif
+
+#ifdef DOSTORESTATE67
+SHA1_RECOMPRESS(67)
+#endif
+
+#ifdef DOSTORESTATE68
+SHA1_RECOMPRESS(68)
+#endif
+
+#ifdef DOSTORESTATE69
+SHA1_RECOMPRESS(69)
+#endif
+
+#ifdef DOSTORESTATE70
+SHA1_RECOMPRESS(70)
+#endif
+
+#ifdef DOSTORESTATE71
+SHA1_RECOMPRESS(71)
+#endif
+
+#ifdef DOSTORESTATE72
+SHA1_RECOMPRESS(72)
+#endif
+
+#ifdef DOSTORESTATE73
+SHA1_RECOMPRESS(73)
+#endif
+
+#ifdef DOSTORESTATE74
+SHA1_RECOMPRESS(74)
+#endif
+
+#ifdef DOSTORESTATE75
+SHA1_RECOMPRESS(75)
+#endif
+
+#ifdef DOSTORESTATE76
+SHA1_RECOMPRESS(76)
+#endif
+
+#ifdef DOSTORESTATE77
+SHA1_RECOMPRESS(77)
+#endif
+
+#ifdef DOSTORESTATE78
+SHA1_RECOMPRESS(78)
+#endif
+
+#ifdef DOSTORESTATE79
+SHA1_RECOMPRESS(79)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+static void sha1_recompression_step(uint32_t step, uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5])
+{
+ switch (step)
+ {
+#ifdef DOSTORESTATE0
+ case 0:
+ sha1recompress_fast_0(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE1
+ case 1:
+ sha1recompress_fast_1(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE2
+ case 2:
+ sha1recompress_fast_2(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE3
+ case 3:
+ sha1recompress_fast_3(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE4
+ case 4:
+ sha1recompress_fast_4(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE5
+ case 5:
+ sha1recompress_fast_5(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE6
+ case 6:
+ sha1recompress_fast_6(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE7
+ case 7:
+ sha1recompress_fast_7(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE8
+ case 8:
+ sha1recompress_fast_8(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE9
+ case 9:
+ sha1recompress_fast_9(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE10
+ case 10:
+ sha1recompress_fast_10(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE11
+ case 11:
+ sha1recompress_fast_11(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE12
+ case 12:
+ sha1recompress_fast_12(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE13
+ case 13:
+ sha1recompress_fast_13(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE14
+ case 14:
+ sha1recompress_fast_14(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE15
+ case 15:
+ sha1recompress_fast_15(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE16
+ case 16:
+ sha1recompress_fast_16(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE17
+ case 17:
+ sha1recompress_fast_17(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE18
+ case 18:
+ sha1recompress_fast_18(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE19
+ case 19:
+ sha1recompress_fast_19(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE20
+ case 20:
+ sha1recompress_fast_20(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE21
+ case 21:
+ sha1recompress_fast_21(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE22
+ case 22:
+ sha1recompress_fast_22(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE23
+ case 23:
+ sha1recompress_fast_23(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE24
+ case 24:
+ sha1recompress_fast_24(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE25
+ case 25:
+ sha1recompress_fast_25(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE26
+ case 26:
+ sha1recompress_fast_26(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE27
+ case 27:
+ sha1recompress_fast_27(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE28
+ case 28:
+ sha1recompress_fast_28(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE29
+ case 29:
+ sha1recompress_fast_29(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE30
+ case 30:
+ sha1recompress_fast_30(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE31
+ case 31:
+ sha1recompress_fast_31(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE32
+ case 32:
+ sha1recompress_fast_32(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE33
+ case 33:
+ sha1recompress_fast_33(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE34
+ case 34:
+ sha1recompress_fast_34(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE35
+ case 35:
+ sha1recompress_fast_35(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE36
+ case 36:
+ sha1recompress_fast_36(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE37
+ case 37:
+ sha1recompress_fast_37(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE38
+ case 38:
+ sha1recompress_fast_38(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE39
+ case 39:
+ sha1recompress_fast_39(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE40
+ case 40:
+ sha1recompress_fast_40(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE41
+ case 41:
+ sha1recompress_fast_41(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE42
+ case 42:
+ sha1recompress_fast_42(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE43
+ case 43:
+ sha1recompress_fast_43(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE44
+ case 44:
+ sha1recompress_fast_44(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE45
+ case 45:
+ sha1recompress_fast_45(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE46
+ case 46:
+ sha1recompress_fast_46(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE47
+ case 47:
+ sha1recompress_fast_47(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE48
+ case 48:
+ sha1recompress_fast_48(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE49
+ case 49:
+ sha1recompress_fast_49(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE50
+ case 50:
+ sha1recompress_fast_50(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE51
+ case 51:
+ sha1recompress_fast_51(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE52
+ case 52:
+ sha1recompress_fast_52(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE53
+ case 53:
+ sha1recompress_fast_53(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE54
+ case 54:
+ sha1recompress_fast_54(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE55
+ case 55:
+ sha1recompress_fast_55(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE56
+ case 56:
+ sha1recompress_fast_56(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE57
+ case 57:
+ sha1recompress_fast_57(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE58
+ case 58:
+ sha1recompress_fast_58(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE59
+ case 59:
+ sha1recompress_fast_59(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE60
+ case 60:
+ sha1recompress_fast_60(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE61
+ case 61:
+ sha1recompress_fast_61(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE62
+ case 62:
+ sha1recompress_fast_62(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE63
+ case 63:
+ sha1recompress_fast_63(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE64
+ case 64:
+ sha1recompress_fast_64(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE65
+ case 65:
+ sha1recompress_fast_65(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE66
+ case 66:
+ sha1recompress_fast_66(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE67
+ case 67:
+ sha1recompress_fast_67(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE68
+ case 68:
+ sha1recompress_fast_68(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE69
+ case 69:
+ sha1recompress_fast_69(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE70
+ case 70:
+ sha1recompress_fast_70(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE71
+ case 71:
+ sha1recompress_fast_71(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE72
+ case 72:
+ sha1recompress_fast_72(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE73
+ case 73:
+ sha1recompress_fast_73(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE74
+ case 74:
+ sha1recompress_fast_74(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE75
+ case 75:
+ sha1recompress_fast_75(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE76
+ case 76:
+ sha1recompress_fast_76(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE77
+ case 77:
+ sha1recompress_fast_77(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE78
+ case 78:
+ sha1recompress_fast_78(ihvin, ihvout, me2, state);
+ break;
+#endif
+#ifdef DOSTORESTATE79
+ case 79:
+ sha1recompress_fast_79(ihvin, ihvout, me2, state);
+ break;
+#endif
+ default:
+ abort();
+ }
+
+}
+
+
+
+static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16])
+{
+ unsigned i, j;
+ uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF };
+ uint32_t ihvtmp[5];
+
+ ctx->ihv1[0] = ctx->ihv[0];
+ ctx->ihv1[1] = ctx->ihv[1];
+ ctx->ihv1[2] = ctx->ihv[2];
+ ctx->ihv1[3] = ctx->ihv[3];
+ ctx->ihv1[4] = ctx->ihv[4];
+
+ sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states);
+
+ if (ctx->detect_coll)
+ {
+ if (ctx->ubc_check)
+ {
+ ubc_check(ctx->m1, ubc_dv_mask);
+ }
+
+ if (ubc_dv_mask[0] != 0)
+ {
+ for (i = 0; sha1_dvs[i].dvType != 0; ++i)
+ {
+ if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb))
+ {
+ for (j = 0; j < 80; ++j)
+ ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j];
+
+ sha1_recompression_step(sha1_dvs[i].testt, ctx->ihv2, ihvtmp, ctx->m2, ctx->states[sha1_dvs[i].testt]);
+
+ /* to verify SHA-1 collision detection code with collisions for reduced-step SHA-1 */
+ if ((0 == ((ihvtmp[0] ^ ctx->ihv[0]) | (ihvtmp[1] ^ ctx->ihv[1]) | (ihvtmp[2] ^ ctx->ihv[2]) | (ihvtmp[3] ^ ctx->ihv[3]) | (ihvtmp[4] ^ ctx->ihv[4])))
+ || (ctx->reduced_round_coll && 0==((ctx->ihv1[0] ^ ctx->ihv2[0]) | (ctx->ihv1[1] ^ ctx->ihv2[1]) | (ctx->ihv1[2] ^ ctx->ihv2[2]) | (ctx->ihv1[3] ^ ctx->ihv2[3]) | (ctx->ihv1[4] ^ ctx->ihv2[4]))))
+ {
+ ctx->found_collision = 1;
+
+ if (ctx->safe_hash)
+ {
+ sha1_compression_W(ctx->ihv, ctx->m1);
+ sha1_compression_W(ctx->ihv, ctx->m1);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void SHA1DCInit(SHA1_CTX* ctx)
+{
+ ctx->total = 0;
+ ctx->ihv[0] = 0x67452301;
+ ctx->ihv[1] = 0xEFCDAB89;
+ ctx->ihv[2] = 0x98BADCFE;
+ ctx->ihv[3] = 0x10325476;
+ ctx->ihv[4] = 0xC3D2E1F0;
+ ctx->found_collision = 0;
+ ctx->safe_hash = SHA1DC_INIT_SAFE_HASH_DEFAULT;
+ ctx->ubc_check = 1;
+ ctx->detect_coll = 1;
+ ctx->reduced_round_coll = 0;
+ ctx->callback = NULL;
+}
+
+void SHA1DCSetSafeHash(SHA1_CTX* ctx, int safehash)
+{
+ if (safehash)
+ ctx->safe_hash = 1;
+ else
+ ctx->safe_hash = 0;
+}
+
+
+void SHA1DCSetUseUBC(SHA1_CTX* ctx, int ubc_check)
+{
+ if (ubc_check)
+ ctx->ubc_check = 1;
+ else
+ ctx->ubc_check = 0;
+}
+
+void SHA1DCSetUseDetectColl(SHA1_CTX* ctx, int detect_coll)
+{
+ if (detect_coll)
+ ctx->detect_coll = 1;
+ else
+ ctx->detect_coll = 0;
+}
+
+void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX* ctx, int reduced_round_coll)
+{
+ if (reduced_round_coll)
+ ctx->reduced_round_coll = 1;
+ else
+ ctx->reduced_round_coll = 0;
+}
+
+void SHA1DCSetCallback(SHA1_CTX* ctx, collision_block_callback callback)
+{
+ ctx->callback = callback;
+}
+
+void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len)
+{
+ unsigned left, fill;
+
+ if (len == 0)
+ return;
+
+ left = ctx->total & 63;
+ fill = 64 - left;
+
+ if (left && len >= fill)
+ {
+ ctx->total += fill;
+ memcpy(ctx->buffer + left, buf, fill);
+ sha1_process(ctx, (uint32_t*)(ctx->buffer));
+ buf += fill;
+ len -= fill;
+ left = 0;
+ }
+ while (len >= 64)
+ {
+ ctx->total += 64;
+
+#if defined(SHA1DC_ALLOW_UNALIGNED_ACCESS)
+ sha1_process(ctx, (uint32_t*)(buf));
+#else
+ memcpy(ctx->buffer, buf, 64);
+ sha1_process(ctx, (uint32_t*)(ctx->buffer));
+#endif /* defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) */
+ buf += 64;
+ len -= 64;
+ }
+ if (len > 0)
+ {
+ ctx->total += len;
+ memcpy(ctx->buffer + left, buf, len);
+ }
+}
+
+static const unsigned char sha1_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx)
+{
+ uint32_t last = ctx->total & 63;
+ uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
+ uint64_t total;
+ SHA1DCUpdate(ctx, (const char*)(sha1_padding), padn);
+
+ total = ctx->total - padn;
+ total <<= 3;
+ ctx->buffer[56] = (unsigned char)(total >> 56);
+ ctx->buffer[57] = (unsigned char)(total >> 48);
+ ctx->buffer[58] = (unsigned char)(total >> 40);
+ ctx->buffer[59] = (unsigned char)(total >> 32);
+ ctx->buffer[60] = (unsigned char)(total >> 24);
+ ctx->buffer[61] = (unsigned char)(total >> 16);
+ ctx->buffer[62] = (unsigned char)(total >> 8);
+ ctx->buffer[63] = (unsigned char)(total);
+ sha1_process(ctx, (uint32_t*)(ctx->buffer));
+ output[0] = (unsigned char)(ctx->ihv[0] >> 24);
+ output[1] = (unsigned char)(ctx->ihv[0] >> 16);
+ output[2] = (unsigned char)(ctx->ihv[0] >> 8);
+ output[3] = (unsigned char)(ctx->ihv[0]);
+ output[4] = (unsigned char)(ctx->ihv[1] >> 24);
+ output[5] = (unsigned char)(ctx->ihv[1] >> 16);
+ output[6] = (unsigned char)(ctx->ihv[1] >> 8);
+ output[7] = (unsigned char)(ctx->ihv[1]);
+ output[8] = (unsigned char)(ctx->ihv[2] >> 24);
+ output[9] = (unsigned char)(ctx->ihv[2] >> 16);
+ output[10] = (unsigned char)(ctx->ihv[2] >> 8);
+ output[11] = (unsigned char)(ctx->ihv[2]);
+ output[12] = (unsigned char)(ctx->ihv[3] >> 24);
+ output[13] = (unsigned char)(ctx->ihv[3] >> 16);
+ output[14] = (unsigned char)(ctx->ihv[3] >> 8);
+ output[15] = (unsigned char)(ctx->ihv[3]);
+ output[16] = (unsigned char)(ctx->ihv[4] >> 24);
+ output[17] = (unsigned char)(ctx->ihv[4] >> 16);
+ output[18] = (unsigned char)(ctx->ihv[4] >> 8);
+ output[19] = (unsigned char)(ctx->ihv[4]);
+ return ctx->found_collision;
+}
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C
+#endif
--- /dev/null
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+#ifndef SHA1DC_SHA1_H
+#define SHA1DC_SHA1_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <stdint.h>
+#endif
+
+/* sha-1 compression function that takes an already expanded message, and additionally store intermediate states */
+/* only stores states ii (the state between step ii-1 and step ii) when DOSTORESTATEii is defined in ubc_check.h */
+void sha1_compression_states(uint32_t[5], const uint32_t[16], uint32_t[80], uint32_t[80][5]);
+
+/*
+// Function type for sha1_recompression_step_T (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]).
+// Where 0 <= T < 80
+// me2 is an expanded message (the expansion of an original message block XOR'ed with a disturbance vector's message block difference.)
+// state is the internal state (a,b,c,d,e) before step T of the SHA-1 compression function while processing the original message block.
+// The function will return:
+// ihvin: The reconstructed input chaining value.
+// ihvout: The reconstructed output chaining value.
+*/
+typedef void(*sha1_recompression_type)(uint32_t*, uint32_t*, const uint32_t*, const uint32_t*);
+
+/* A callback function type that can be set to be called when a collision block has been found: */
+/* void collision_block_callback(uint64_t byteoffset, const uint32_t ihvin1[5], const uint32_t ihvin2[5], const uint32_t m1[80], const uint32_t m2[80]) */
+typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*);
+
+/* The SHA-1 context. */
+typedef struct {
+ uint64_t total;
+ uint32_t ihv[5];
+ unsigned char buffer[64];
+ int found_collision;
+ int safe_hash;
+ int detect_coll;
+ int ubc_check;
+ int reduced_round_coll;
+ collision_block_callback callback;
+
+ uint32_t ihv1[5];
+ uint32_t ihv2[5];
+ uint32_t m1[80];
+ uint32_t m2[80];
+ uint32_t states[80][5];
+} SHA1_CTX;
+
+/* Initialize SHA-1 context. */
+void SHA1DCInit(SHA1_CTX*);
+
+/*
+ Function to enable safe SHA-1 hashing:
+ Collision attacks are thwarted by hashing a detected near-collision block 3 times.
+ Think of it as extending SHA-1 from 80-steps to 240-steps for such blocks:
+ The best collision attacks against SHA-1 have complexity about 2^60,
+ thus for 240-steps an immediate lower-bound for the best cryptanalytic attacks would be 2^180.
+ An attacker would be better off using a generic birthday search of complexity 2^80.
+
+ Enabling safe SHA-1 hashing will result in the correct SHA-1 hash for messages where no collision attack was detected,
+ but it will result in a different SHA-1 hash for messages where a collision attack was detected.
+ This will automatically invalidate SHA-1 based digital signature forgeries.
+ Enabled by default.
+*/
+void SHA1DCSetSafeHash(SHA1_CTX*, int);
+
+/*
+ Function to disable or enable the use of Unavoidable Bitconditions (provides a significant speed up).
+ Enabled by default
+ */
+void SHA1DCSetUseUBC(SHA1_CTX*, int);
+
+/*
+ Function to disable or enable the use of Collision Detection.
+ Enabled by default.
+ */
+void SHA1DCSetUseDetectColl(SHA1_CTX*, int);
+
+/* function to disable or enable the detection of reduced-round SHA-1 collisions */
+/* disabled by default */
+void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX*, int);
+
+/* function to set a callback function, pass NULL to disable */
+/* by default no callback set */
+void SHA1DCSetCallback(SHA1_CTX*, collision_block_callback);
+
+/* update SHA-1 context with buffer contents */
+void SHA1DCUpdate(SHA1_CTX*, const char*, size_t);
+
+/* obtain SHA-1 hash from SHA-1 context */
+/* returns: 0 = no collision detected, otherwise = collision found => warn user for active attack */
+int SHA1DCFinal(unsigned char[20], SHA1_CTX*);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H
+#endif
+
+#endif
--- /dev/null
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+/*
+// this file was generated by the 'parse_bitrel' program in the tools section
+// using the data files from directory 'tools/data/3565'
+//
+// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check
+// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper)
+// dm[80] is the expanded message block XOR-difference defined by the DV
+// testt is the step to do the recompression from for collision detection
+// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check
+//
+// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs
+// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met
+// thus one needs to do the recompression check for each DV that has its bit set
+//
+// ubc_check is programmatically generated and the unavoidable bitconditions have been hardcoded
+// a directly verifiable version named ubc_check_verify can be found in ubc_check_verify.c
+// ubc_check has been verified against ubc_check_verify using the 'ubc_check_test' program in the tools section
+*/
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <stdint.h>
+#endif
+#ifdef SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C
+#include SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C
+#endif
+#include "ubc_check.h"
+
+static const uint32_t DV_I_43_0_bit = (uint32_t)(1) << 0;
+static const uint32_t DV_I_44_0_bit = (uint32_t)(1) << 1;
+static const uint32_t DV_I_45_0_bit = (uint32_t)(1) << 2;
+static const uint32_t DV_I_46_0_bit = (uint32_t)(1) << 3;
+static const uint32_t DV_I_46_2_bit = (uint32_t)(1) << 4;
+static const uint32_t DV_I_47_0_bit = (uint32_t)(1) << 5;
+static const uint32_t DV_I_47_2_bit = (uint32_t)(1) << 6;
+static const uint32_t DV_I_48_0_bit = (uint32_t)(1) << 7;
+static const uint32_t DV_I_48_2_bit = (uint32_t)(1) << 8;
+static const uint32_t DV_I_49_0_bit = (uint32_t)(1) << 9;
+static const uint32_t DV_I_49_2_bit = (uint32_t)(1) << 10;
+static const uint32_t DV_I_50_0_bit = (uint32_t)(1) << 11;
+static const uint32_t DV_I_50_2_bit = (uint32_t)(1) << 12;
+static const uint32_t DV_I_51_0_bit = (uint32_t)(1) << 13;
+static const uint32_t DV_I_51_2_bit = (uint32_t)(1) << 14;
+static const uint32_t DV_I_52_0_bit = (uint32_t)(1) << 15;
+static const uint32_t DV_II_45_0_bit = (uint32_t)(1) << 16;
+static const uint32_t DV_II_46_0_bit = (uint32_t)(1) << 17;
+static const uint32_t DV_II_46_2_bit = (uint32_t)(1) << 18;
+static const uint32_t DV_II_47_0_bit = (uint32_t)(1) << 19;
+static const uint32_t DV_II_48_0_bit = (uint32_t)(1) << 20;
+static const uint32_t DV_II_49_0_bit = (uint32_t)(1) << 21;
+static const uint32_t DV_II_49_2_bit = (uint32_t)(1) << 22;
+static const uint32_t DV_II_50_0_bit = (uint32_t)(1) << 23;
+static const uint32_t DV_II_50_2_bit = (uint32_t)(1) << 24;
+static const uint32_t DV_II_51_0_bit = (uint32_t)(1) << 25;
+static const uint32_t DV_II_51_2_bit = (uint32_t)(1) << 26;
+static const uint32_t DV_II_52_0_bit = (uint32_t)(1) << 27;
+static const uint32_t DV_II_53_0_bit = (uint32_t)(1) << 28;
+static const uint32_t DV_II_54_0_bit = (uint32_t)(1) << 29;
+static const uint32_t DV_II_55_0_bit = (uint32_t)(1) << 30;
+static const uint32_t DV_II_56_0_bit = (uint32_t)(1) << 31;
+
+dv_info_t sha1_dvs[] =
+{
+ {1,43,0,58,0,0, { 0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161,0x80000599 } }
+, {1,44,0,58,0,1, { 0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161 } }
+, {1,45,0,58,0,2, { 0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803 } }
+, {1,46,0,58,0,3, { 0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c } }
+, {1,46,2,58,0,4, { 0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a,0x00000132 } }
+, {1,47,0,58,0,5, { 0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6 } }
+, {1,47,2,58,0,6, { 0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a } }
+, {1,48,0,58,0,7, { 0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408 } }
+, {1,48,2,58,0,8, { 0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020 } }
+, {1,49,0,58,0,9, { 0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164 } }
+, {1,49,2,58,0,10, { 0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590 } }
+, {1,50,0,65,0,11, { 0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018 } }
+, {1,50,2,65,0,12, { 0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060 } }
+, {1,51,0,65,0,13, { 0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202 } }
+, {1,51,2,65,0,14, { 0xa0000003,0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a } }
+, {1,52,0,65,0,15, { 0x04000010,0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012 } }
+, {2,45,0,58,0,16, { 0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054,0x00000967 } }
+, {2,46,0,58,0,17, { 0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054 } }
+, {2,46,2,58,0,18, { 0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6,0x0000106a,0x00000b90,0x00000152 } }
+, {2,47,0,58,0,19, { 0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4 } }
+, {2,48,0,58,0,20, { 0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a } }
+, {2,49,0,58,0,21, { 0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d } }
+, {2,49,2,58,0,22, { 0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6 } }
+, {2,50,0,65,0,23, { 0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b } }
+, {2,50,2,65,0,24, { 0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c } }
+, {2,51,0,65,0,25, { 0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b } }
+, {2,51,2,65,0,26, { 0x00000043,0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e } }
+, {2,52,0,65,0,27, { 0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014 } }
+, {2,53,0,65,0,28, { 0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089 } }
+, {2,54,0,65,0,29, { 0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107 } }
+, {2,55,0,65,0,30, { 0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b } }
+, {2,56,0,65,0,31, { 0x2600001a,0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046 } }
+, {0,0,0,0,0,0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+};
+void ubc_check(const uint32_t W[80], uint32_t dvmask[1])
+{
+ uint32_t mask = ~((uint32_t)(0));
+ mask &= (((((W[44]^W[45])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_I_51_0_bit|DV_I_52_0_bit|DV_II_45_0_bit|DV_II_46_0_bit|DV_II_50_0_bit|DV_II_51_0_bit));
+ mask &= (((((W[49]^W[50])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_II_45_0_bit|DV_II_50_0_bit|DV_II_51_0_bit|DV_II_55_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[48]^W[49])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_52_0_bit|DV_II_49_0_bit|DV_II_50_0_bit|DV_II_54_0_bit|DV_II_55_0_bit));
+ mask &= ((((W[47]^(W[50]>>25))&(1<<4))-(1<<4)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_51_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[47]^W[48])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_51_0_bit|DV_II_48_0_bit|DV_II_49_0_bit|DV_II_53_0_bit|DV_II_54_0_bit));
+ mask &= (((((W[46]>>4)^(W[49]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_50_0_bit|DV_II_55_0_bit));
+ mask &= (((((W[46]^W[47])>>29)&1)-1) | ~(DV_I_43_0_bit|DV_I_50_0_bit|DV_II_47_0_bit|DV_II_48_0_bit|DV_II_52_0_bit|DV_II_53_0_bit));
+ mask &= (((((W[45]>>4)^(W[48]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_49_0_bit|DV_II_54_0_bit));
+ mask &= (((((W[45]^W[46])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_51_0_bit|DV_II_52_0_bit));
+ mask &= (((((W[44]>>4)^(W[47]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_53_0_bit));
+ mask &= (((((W[43]>>4)^(W[46]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_52_0_bit));
+ mask &= (((((W[43]^W[44])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_I_50_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_49_0_bit|DV_II_50_0_bit));
+ mask &= (((((W[42]>>4)^(W[45]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_51_0_bit));
+ mask &= (((((W[41]>>4)^(W[44]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_50_0_bit));
+ mask &= (((((W[40]^W[41])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_47_0_bit|DV_I_48_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[54]^W[55])>>29)&1)-1) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_50_0_bit|DV_II_55_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[53]^W[54])>>29)&1)-1) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_49_0_bit|DV_II_54_0_bit|DV_II_55_0_bit));
+ mask &= (((((W[52]^W[53])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit|DV_II_53_0_bit|DV_II_54_0_bit));
+ mask &= ((((W[50]^(W[53]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_48_0_bit|DV_II_54_0_bit));
+ mask &= (((((W[50]^W[51])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_II_46_0_bit|DV_II_51_0_bit|DV_II_52_0_bit|DV_II_56_0_bit));
+ mask &= ((((W[49]^(W[52]>>25))&(1<<4))-(1<<4)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_47_0_bit|DV_II_53_0_bit));
+ mask &= ((((W[48]^(W[51]>>25))&(1<<4))-(1<<4)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_52_0_bit));
+ mask &= (((((W[42]^W[43])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_49_0_bit));
+ mask &= (((((W[41]^W[42])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_48_0_bit));
+ mask &= (((((W[40]>>4)^(W[43]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_50_0_bit|DV_II_49_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[39]>>4)^(W[42]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_49_0_bit|DV_II_48_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit))
+ mask &= (((((W[38]>>4)^(W[41]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit));
+ mask &= (((((W[37]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_47_0_bit|DV_II_46_0_bit|DV_II_53_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit))
+ mask &= (((((W[55]^W[56])>>29)&1)-1) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit))
+ mask &= ((((W[52]^(W[55]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit));
+ if (mask & (DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit))
+ mask &= ((((W[51]^(W[54]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit))
+ mask &= (((((W[51]^W[52])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit));
+ if (mask & (DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit))
+ mask &= (((((W[36]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit))
+ mask &= ((0-(((W[53]^W[56])>>29)&1)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit));
+ if (mask & (DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit))
+ mask &= ((0-(((W[51]^W[54])>>29)&1)) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit));
+ if (mask & (DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit))
+ mask &= ((0-(((W[50]^W[52])>>29)&1)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit));
+ if (mask & (DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit))
+ mask &= ((0-(((W[49]^W[51])>>29)&1)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit));
+ if (mask & (DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit))
+ mask &= ((0-(((W[48]^W[50])>>29)&1)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit));
+ if (mask & (DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit))
+ mask &= ((0-(((W[47]^W[49])>>29)&1)) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit));
+ if (mask & (DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit))
+ mask &= ((0-(((W[46]^W[48])>>29)&1)) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit));
+ mask &= ((((W[45]^W[47])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit|DV_I_51_2_bit));
+ if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit))
+ mask &= ((0-(((W[45]^W[47])>>29)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit));
+ mask &= (((((W[44]^W[46])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit|DV_I_50_2_bit));
+ if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit))
+ mask &= ((0-(((W[44]^W[46])>>29)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit));
+ mask &= ((0-((W[41]^(W[42]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_II_46_2_bit|DV_II_51_2_bit));
+ mask &= ((0-((W[40]^(W[41]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_51_2_bit|DV_II_50_2_bit));
+ if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit))
+ mask &= ((0-(((W[40]^W[42])>>4)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit));
+ mask &= ((0-((W[39]^(W[40]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_50_2_bit|DV_II_49_2_bit));
+ if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit))
+ mask &= ((0-(((W[39]^W[41])>>4)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit));
+ if (mask & (DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit))
+ mask &= ((0-(((W[38]^W[40])>>4)&1)) | ~(DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit));
+ if (mask & (DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit))
+ mask &= ((0-(((W[37]^W[39])>>4)&1)) | ~(DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit));
+ mask &= ((0-((W[36]^(W[37]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_50_2_bit|DV_II_46_2_bit));
+ if (mask & (DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit))
+ mask &= (((((W[35]>>4)^(W[39]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit));
+ if (mask & (DV_I_48_0_bit|DV_II_48_0_bit))
+ mask &= ((0-((W[63]^(W[64]>>5))&(1<<0))) | ~(DV_I_48_0_bit|DV_II_48_0_bit));
+ if (mask & (DV_I_45_0_bit|DV_II_45_0_bit))
+ mask &= ((0-((W[63]^(W[64]>>5))&(1<<1))) | ~(DV_I_45_0_bit|DV_II_45_0_bit));
+ if (mask & (DV_I_47_0_bit|DV_II_47_0_bit))
+ mask &= ((0-((W[62]^(W[63]>>5))&(1<<0))) | ~(DV_I_47_0_bit|DV_II_47_0_bit));
+ if (mask & (DV_I_46_0_bit|DV_II_46_0_bit))
+ mask &= ((0-((W[61]^(W[62]>>5))&(1<<0))) | ~(DV_I_46_0_bit|DV_II_46_0_bit));
+ mask &= ((0-((W[61]^(W[62]>>5))&(1<<2))) | ~(DV_I_46_2_bit|DV_II_46_2_bit));
+ if (mask & (DV_I_45_0_bit|DV_II_45_0_bit))
+ mask &= ((0-((W[60]^(W[61]>>5))&(1<<0))) | ~(DV_I_45_0_bit|DV_II_45_0_bit));
+ if (mask & (DV_II_51_0_bit|DV_II_54_0_bit))
+ mask &= (((((W[58]^W[59])>>29)&1)-1) | ~(DV_II_51_0_bit|DV_II_54_0_bit));
+ if (mask & (DV_II_50_0_bit|DV_II_53_0_bit))
+ mask &= (((((W[57]^W[58])>>29)&1)-1) | ~(DV_II_50_0_bit|DV_II_53_0_bit));
+ if (mask & (DV_II_52_0_bit|DV_II_54_0_bit))
+ mask &= ((((W[56]^(W[59]>>25))&(1<<4))-(1<<4)) | ~(DV_II_52_0_bit|DV_II_54_0_bit));
+ if (mask & (DV_II_51_0_bit|DV_II_52_0_bit))
+ mask &= ((0-(((W[56]^W[59])>>29)&1)) | ~(DV_II_51_0_bit|DV_II_52_0_bit));
+ if (mask & (DV_II_49_0_bit|DV_II_52_0_bit))
+ mask &= (((((W[56]^W[57])>>29)&1)-1) | ~(DV_II_49_0_bit|DV_II_52_0_bit));
+ if (mask & (DV_II_51_0_bit|DV_II_53_0_bit))
+ mask &= ((((W[55]^(W[58]>>25))&(1<<4))-(1<<4)) | ~(DV_II_51_0_bit|DV_II_53_0_bit));
+ if (mask & (DV_II_50_0_bit|DV_II_52_0_bit))
+ mask &= ((((W[54]^(W[57]>>25))&(1<<4))-(1<<4)) | ~(DV_II_50_0_bit|DV_II_52_0_bit));
+ if (mask & (DV_II_49_0_bit|DV_II_51_0_bit))
+ mask &= ((((W[53]^(W[56]>>25))&(1<<4))-(1<<4)) | ~(DV_II_49_0_bit|DV_II_51_0_bit));
+ mask &= ((((W[51]^(W[50]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_46_2_bit));
+ mask &= ((((W[48]^W[50])&(1<<6))-(1<<6)) | ~(DV_I_50_2_bit|DV_II_46_2_bit));
+ if (mask & (DV_I_51_0_bit|DV_I_52_0_bit))
+ mask &= ((0-(((W[48]^W[55])>>29)&1)) | ~(DV_I_51_0_bit|DV_I_52_0_bit));
+ mask &= ((((W[47]^W[49])&(1<<6))-(1<<6)) | ~(DV_I_49_2_bit|DV_I_51_2_bit));
+ mask &= ((((W[48]^(W[47]>>5))&(1<<1))-(1<<1)) | ~(DV_I_47_2_bit|DV_II_51_2_bit));
+ mask &= ((((W[46]^W[48])&(1<<6))-(1<<6)) | ~(DV_I_48_2_bit|DV_I_50_2_bit));
+ mask &= ((((W[47]^(W[46]>>5))&(1<<1))-(1<<1)) | ~(DV_I_46_2_bit|DV_II_50_2_bit));
+ mask &= ((0-((W[44]^(W[45]>>5))&(1<<1))) | ~(DV_I_51_2_bit|DV_II_49_2_bit));
+ mask &= ((((W[43]^W[45])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit));
+ mask &= (((((W[42]^W[44])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit));
+ mask &= ((((W[43]^(W[42]>>5))&(1<<1))-(1<<1)) | ~(DV_II_46_2_bit|DV_II_51_2_bit));
+ mask &= ((((W[42]^(W[41]>>5))&(1<<1))-(1<<1)) | ~(DV_I_51_2_bit|DV_II_50_2_bit));
+ mask &= ((((W[41]^(W[40]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_49_2_bit));
+ if (mask & (DV_I_52_0_bit|DV_II_51_0_bit))
+ mask &= ((((W[39]^(W[43]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_51_0_bit));
+ if (mask & (DV_I_51_0_bit|DV_II_50_0_bit))
+ mask &= ((((W[38]^(W[42]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_50_0_bit));
+ if (mask & (DV_I_48_2_bit|DV_I_51_2_bit))
+ mask &= ((0-((W[37]^(W[38]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_I_51_2_bit));
+ if (mask & (DV_I_50_0_bit|DV_II_49_0_bit))
+ mask &= ((((W[37]^(W[41]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_II_49_0_bit));
+ if (mask & (DV_II_52_0_bit|DV_II_54_0_bit))
+ mask &= ((0-((W[36]^W[38])&(1<<4))) | ~(DV_II_52_0_bit|DV_II_54_0_bit));
+ mask &= ((0-((W[35]^(W[36]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_49_2_bit));
+ if (mask & (DV_I_51_0_bit|DV_II_47_0_bit))
+ mask &= ((((W[35]^(W[39]>>25))&(1<<3))-(1<<3)) | ~(DV_I_51_0_bit|DV_II_47_0_bit));
+if (mask) {
+
+ if (mask & DV_I_43_0_bit)
+ if (
+ !((W[61]^(W[62]>>5)) & (1<<1))
+ || !(!((W[59]^(W[63]>>25)) & (1<<5)))
+ || !((W[58]^(W[63]>>30)) & (1<<0))
+ ) mask &= ~DV_I_43_0_bit;
+ if (mask & DV_I_44_0_bit)
+ if (
+ !((W[62]^(W[63]>>5)) & (1<<1))
+ || !(!((W[60]^(W[64]>>25)) & (1<<5)))
+ || !((W[59]^(W[64]>>30)) & (1<<0))
+ ) mask &= ~DV_I_44_0_bit;
+ if (mask & DV_I_46_2_bit)
+ mask &= ((~((W[40]^W[42])>>2)) | ~DV_I_46_2_bit);
+ if (mask & DV_I_47_2_bit)
+ if (
+ !((W[62]^(W[63]>>5)) & (1<<2))
+ || !(!((W[41]^W[43]) & (1<<6)))
+ ) mask &= ~DV_I_47_2_bit;
+ if (mask & DV_I_48_2_bit)
+ if (
+ !((W[63]^(W[64]>>5)) & (1<<2))
+ || !(!((W[48]^(W[49]<<5)) & (1<<6)))
+ ) mask &= ~DV_I_48_2_bit;
+ if (mask & DV_I_49_2_bit)
+ if (
+ !(!((W[49]^(W[50]<<5)) & (1<<6)))
+ || !((W[42]^W[50]) & (1<<1))
+ || !(!((W[39]^(W[40]<<5)) & (1<<6)))
+ || !((W[38]^W[40]) & (1<<1))
+ ) mask &= ~DV_I_49_2_bit;
+ if (mask & DV_I_50_0_bit)
+ mask &= ((((W[36]^W[37])<<7)) | ~DV_I_50_0_bit);
+ if (mask & DV_I_50_2_bit)
+ mask &= ((((W[43]^W[51])<<11)) | ~DV_I_50_2_bit);
+ if (mask & DV_I_51_0_bit)
+ mask &= ((((W[37]^W[38])<<9)) | ~DV_I_51_0_bit);
+ if (mask & DV_I_51_2_bit)
+ if (
+ !(!((W[51]^(W[52]<<5)) & (1<<6)))
+ || !(!((W[49]^W[51]) & (1<<6)))
+ || !(!((W[37]^(W[37]>>5)) & (1<<1)))
+ || !(!((W[35]^(W[39]>>25)) & (1<<5)))
+ ) mask &= ~DV_I_51_2_bit;
+ if (mask & DV_I_52_0_bit)
+ mask &= ((((W[38]^W[39])<<11)) | ~DV_I_52_0_bit);
+ if (mask & DV_II_46_2_bit)
+ mask &= ((((W[47]^W[51])<<17)) | ~DV_II_46_2_bit);
+ if (mask & DV_II_48_0_bit)
+ if (
+ !(!((W[36]^(W[40]>>25)) & (1<<3)))
+ || !((W[35]^(W[40]<<2)) & (1<<30))
+ ) mask &= ~DV_II_48_0_bit;
+ if (mask & DV_II_49_0_bit)
+ if (
+ !(!((W[37]^(W[41]>>25)) & (1<<3)))
+ || !((W[36]^(W[41]<<2)) & (1<<30))
+ ) mask &= ~DV_II_49_0_bit;
+ if (mask & DV_II_49_2_bit)
+ if (
+ !(!((W[53]^(W[54]<<5)) & (1<<6)))
+ || !(!((W[51]^W[53]) & (1<<6)))
+ || !((W[50]^W[54]) & (1<<1))
+ || !(!((W[45]^(W[46]<<5)) & (1<<6)))
+ || !(!((W[37]^(W[41]>>25)) & (1<<5)))
+ || !((W[36]^(W[41]>>30)) & (1<<0))
+ ) mask &= ~DV_II_49_2_bit;
+ if (mask & DV_II_50_0_bit)
+ if (
+ !((W[55]^W[58]) & (1<<29))
+ || !(!((W[38]^(W[42]>>25)) & (1<<3)))
+ || !((W[37]^(W[42]<<2)) & (1<<30))
+ ) mask &= ~DV_II_50_0_bit;
+ if (mask & DV_II_50_2_bit)
+ if (
+ !(!((W[54]^(W[55]<<5)) & (1<<6)))
+ || !(!((W[52]^W[54]) & (1<<6)))
+ || !((W[51]^W[55]) & (1<<1))
+ || !((W[45]^W[47]) & (1<<1))
+ || !(!((W[38]^(W[42]>>25)) & (1<<5)))
+ || !((W[37]^(W[42]>>30)) & (1<<0))
+ ) mask &= ~DV_II_50_2_bit;
+ if (mask & DV_II_51_0_bit)
+ if (
+ !(!((W[39]^(W[43]>>25)) & (1<<3)))
+ || !((W[38]^(W[43]<<2)) & (1<<30))
+ ) mask &= ~DV_II_51_0_bit;
+ if (mask & DV_II_51_2_bit)
+ if (
+ !(!((W[55]^(W[56]<<5)) & (1<<6)))
+ || !(!((W[53]^W[55]) & (1<<6)))
+ || !((W[52]^W[56]) & (1<<1))
+ || !((W[46]^W[48]) & (1<<1))
+ || !(!((W[39]^(W[43]>>25)) & (1<<5)))
+ || !((W[38]^(W[43]>>30)) & (1<<0))
+ ) mask &= ~DV_II_51_2_bit;
+ if (mask & DV_II_52_0_bit)
+ if (
+ !(!((W[59]^W[60]) & (1<<29)))
+ || !(!((W[40]^(W[44]>>25)) & (1<<3)))
+ || !(!((W[40]^(W[44]>>25)) & (1<<4)))
+ || !((W[39]^(W[44]<<2)) & (1<<30))
+ ) mask &= ~DV_II_52_0_bit;
+ if (mask & DV_II_53_0_bit)
+ if (
+ !((W[58]^W[61]) & (1<<29))
+ || !(!((W[57]^(W[61]>>25)) & (1<<4)))
+ || !(!((W[41]^(W[45]>>25)) & (1<<3)))
+ || !(!((W[41]^(W[45]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_53_0_bit;
+ if (mask & DV_II_54_0_bit)
+ if (
+ !(!((W[58]^(W[62]>>25)) & (1<<4)))
+ || !(!((W[42]^(W[46]>>25)) & (1<<3)))
+ || !(!((W[42]^(W[46]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_54_0_bit;
+ if (mask & DV_II_55_0_bit)
+ if (
+ !(!((W[59]^(W[63]>>25)) & (1<<4)))
+ || !(!((W[57]^(W[59]>>25)) & (1<<4)))
+ || !(!((W[43]^(W[47]>>25)) & (1<<3)))
+ || !(!((W[43]^(W[47]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_55_0_bit;
+ if (mask & DV_II_56_0_bit)
+ if (
+ !(!((W[60]^(W[64]>>25)) & (1<<4)))
+ || !(!((W[44]^(W[48]>>25)) & (1<<3)))
+ || !(!((W[44]^(W[48]>>25)) & (1<<4)))
+ ) mask &= ~DV_II_56_0_bit;
+}
+
+ dvmask[0]=mask;
+}
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C
+#endif
--- /dev/null
+/***
+* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
+* Distributed under the MIT Software License.
+* See accompanying file LICENSE.txt or copy at
+* https://opensource.org/licenses/MIT
+***/
+
+/*
+// this file was generated by the 'parse_bitrel' program in the tools section
+// using the data files from directory 'tools/data/3565'
+//
+// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check
+// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper)
+// dm[80] is the expanded message block XOR-difference defined by the DV
+// testt is the step to do the recompression from for collision detection
+// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check
+//
+// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs
+// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met
+// thus one needs to do the recompression check for each DV that has its bit set
+*/
+
+#ifndef SHA1DC_UBC_CHECK_H
+#define SHA1DC_UBC_CHECK_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef SHA1DC_NO_STANDARD_INCLUDES
+#include <stdint.h>
+#endif
+
+#define DVMASKSIZE 1
+typedef struct { int dvType; int dvK; int dvB; int testt; int maski; int maskb; uint32_t dm[80]; } dv_info_t;
+extern dv_info_t sha1_dvs[];
+void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]);
+
+#define DOSTORESTATE58
+#define DOSTORESTATE65
+
+#define CHECK_DVMASK(_DVMASK) (0 != _DVMASK[0])
+
+#if defined(__cplusplus)
+}
+#endif
+
+#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H
+#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "win32.h"
+
+#include "global.h"
+
+#include <wincrypt.h>
+#include <strsafe.h>
+
+#define GIT_HASH_CNG_DLL_NAME "bcrypt.dll"
+
+/* BCRYPT_SHA1_ALGORITHM */
+#define GIT_HASH_CNG_HASH_TYPE L"SHA1"
+
+/* BCRYPT_OBJECT_LENGTH */
+#define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength"
+
+/* BCRYPT_HASH_REUSEABLE_FLAGS */
+#define GIT_HASH_CNG_HASH_REUSABLE 0x00000020
+
+static git_hash_prov hash_prov = {0};
+
+/* Hash initialization */
+
+/* Initialize CNG, if available */
+GIT_INLINE(int) hash_cng_prov_init(void)
+{
+ char dll_path[MAX_PATH];
+ DWORD dll_path_len, size_len;
+
+ /* Only use CNG on Windows 2008 / Vista SP1 or better (Windows 6.0 SP1) */
+ if (!git_has_win32_version(6, 0, 1)) {
+ git_error_set(GIT_ERROR_SHA1, "CryptoNG is not supported on this platform");
+ return -1;
+ }
+
+ /* Load bcrypt.dll explicitly from the system directory */
+ if ((dll_path_len = GetSystemDirectory(dll_path, MAX_PATH)) == 0 ||
+ dll_path_len > MAX_PATH ||
+ StringCchCat(dll_path, MAX_PATH, "\\") < 0 ||
+ StringCchCat(dll_path, MAX_PATH, GIT_HASH_CNG_DLL_NAME) < 0 ||
+ (hash_prov.prov.cng.dll = LoadLibrary(dll_path)) == NULL) {
+ git_error_set(GIT_ERROR_SHA1, "CryptoNG library could not be loaded");
+ return -1;
+ }
+
+ /* Load the function addresses */
+ if ((hash_prov.prov.cng.open_algorithm_provider = (hash_win32_cng_open_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptOpenAlgorithmProvider")) == NULL ||
+ (hash_prov.prov.cng.get_property = (hash_win32_cng_get_property_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptGetProperty")) == NULL ||
+ (hash_prov.prov.cng.create_hash = (hash_win32_cng_create_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCreateHash")) == NULL ||
+ (hash_prov.prov.cng.finish_hash = (hash_win32_cng_finish_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptFinishHash")) == NULL ||
+ (hash_prov.prov.cng.hash_data = (hash_win32_cng_hash_data_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptHashData")) == NULL ||
+ (hash_prov.prov.cng.destroy_hash = (hash_win32_cng_destroy_hash_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptDestroyHash")) == NULL ||
+ (hash_prov.prov.cng.close_algorithm_provider = (hash_win32_cng_close_algorithm_provider_fn)GetProcAddress(hash_prov.prov.cng.dll, "BCryptCloseAlgorithmProvider")) == NULL) {
+ FreeLibrary(hash_prov.prov.cng.dll);
+
+ git_error_set(GIT_ERROR_OS, "CryptoNG functions could not be loaded");
+ return -1;
+ }
+
+ /* Load the SHA1 algorithm */
+ if (hash_prov.prov.cng.open_algorithm_provider(&hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_TYPE, NULL, GIT_HASH_CNG_HASH_REUSABLE) < 0) {
+ FreeLibrary(hash_prov.prov.cng.dll);
+
+ git_error_set(GIT_ERROR_OS, "algorithm provider could not be initialized");
+ return -1;
+ }
+
+ /* Get storage space for the hash object */
+ if (hash_prov.prov.cng.get_property(hash_prov.prov.cng.handle, GIT_HASH_CNG_HASH_OBJECT_LEN, (PBYTE)&hash_prov.prov.cng.hash_object_size, sizeof(DWORD), &size_len, 0) < 0) {
+ hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0);
+ FreeLibrary(hash_prov.prov.cng.dll);
+
+ git_error_set(GIT_ERROR_OS, "algorithm handle could not be found");
+ return -1;
+ }
+
+ hash_prov.type = CNG;
+ return 0;
+}
+
+GIT_INLINE(void) hash_cng_prov_shutdown(void)
+{
+ hash_prov.prov.cng.close_algorithm_provider(hash_prov.prov.cng.handle, 0);
+ FreeLibrary(hash_prov.prov.cng.dll);
+
+ hash_prov.type = INVALID;
+}
+
+/* Initialize CryptoAPI */
+GIT_INLINE(int) hash_cryptoapi_prov_init()
+{
+ if (!CryptAcquireContext(&hash_prov.prov.cryptoapi.handle, NULL, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ git_error_set(GIT_ERROR_OS, "legacy hash context could not be started");
+ return -1;
+ }
+
+ hash_prov.type = CRYPTOAPI;
+ return 0;
+}
+
+GIT_INLINE(void) hash_cryptoapi_prov_shutdown(void)
+{
+ CryptReleaseContext(hash_prov.prov.cryptoapi.handle, 0);
+
+ hash_prov.type = INVALID;
+}
+
+static void sha1_shutdown(void)
+{
+ if (hash_prov.type == CNG)
+ hash_cng_prov_shutdown();
+ else if(hash_prov.type == CRYPTOAPI)
+ hash_cryptoapi_prov_shutdown();
+}
+
+int git_hash_sha1_global_init(void)
+{
+ int error = 0;
+
+ if (hash_prov.type != INVALID)
+ return 0;
+
+ if ((error = hash_cng_prov_init()) < 0)
+ error = hash_cryptoapi_prov_init();
+
+ git__on_shutdown(sha1_shutdown);
+
+ return error;
+}
+
+/* CryptoAPI: available in Windows XP and newer */
+
+GIT_INLINE(int) hash_ctx_cryptoapi_init(git_hash_sha1_ctx *ctx)
+{
+ ctx->type = CRYPTOAPI;
+ ctx->prov = &hash_prov;
+
+ return git_hash_sha1_init(ctx);
+}
+
+GIT_INLINE(int) hash_cryptoapi_init(git_hash_sha1_ctx *ctx)
+{
+ if (ctx->ctx.cryptoapi.valid)
+ CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle);
+
+ if (!CryptCreateHash(ctx->prov->prov.cryptoapi.handle, CALG_SHA1, 0, 0, &ctx->ctx.cryptoapi.hash_handle)) {
+ ctx->ctx.cryptoapi.valid = 0;
+ git_error_set(GIT_ERROR_OS, "legacy hash implementation could not be created");
+ return -1;
+ }
+
+ ctx->ctx.cryptoapi.valid = 1;
+ return 0;
+}
+
+GIT_INLINE(int) hash_cryptoapi_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len)
+{
+ const BYTE *data = (BYTE *)_data;
+
+ assert(ctx->ctx.cryptoapi.valid);
+
+ while (len > 0) {
+ DWORD chunk = (len > MAXDWORD) ? MAXDWORD : (DWORD)len;
+
+ if (!CryptHashData(ctx->ctx.cryptoapi.hash_handle, data, chunk, 0)) {
+ git_error_set(GIT_ERROR_OS, "legacy hash data could not be updated");
+ return -1;
+ }
+
+ data += chunk;
+ len -= chunk;
+ }
+
+ return 0;
+}
+
+GIT_INLINE(int) hash_cryptoapi_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ DWORD len = 20;
+ int error = 0;
+
+ assert(ctx->ctx.cryptoapi.valid);
+
+ if (!CryptGetHashParam(ctx->ctx.cryptoapi.hash_handle, HP_HASHVAL, out->id, &len, 0)) {
+ git_error_set(GIT_ERROR_OS, "legacy hash data could not be finished");
+ error = -1;
+ }
+
+ CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle);
+ ctx->ctx.cryptoapi.valid = 0;
+
+ return error;
+}
+
+GIT_INLINE(void) hash_ctx_cryptoapi_cleanup(git_hash_sha1_ctx *ctx)
+{
+ if (ctx->ctx.cryptoapi.valid)
+ CryptDestroyHash(ctx->ctx.cryptoapi.hash_handle);
+}
+
+/* CNG: Available in Windows Server 2008 and newer */
+
+GIT_INLINE(int) hash_ctx_cng_init(git_hash_sha1_ctx *ctx)
+{
+ if ((ctx->ctx.cng.hash_object = git__malloc(hash_prov.prov.cng.hash_object_size)) == NULL)
+ return -1;
+
+ if (hash_prov.prov.cng.create_hash(hash_prov.prov.cng.handle, &ctx->ctx.cng.hash_handle, ctx->ctx.cng.hash_object, hash_prov.prov.cng.hash_object_size, NULL, 0, 0) < 0) {
+ git__free(ctx->ctx.cng.hash_object);
+
+ git_error_set(GIT_ERROR_OS, "hash implementation could not be created");
+ return -1;
+ }
+
+ ctx->type = CNG;
+ ctx->prov = &hash_prov;
+
+ return 0;
+}
+
+GIT_INLINE(int) hash_cng_init(git_hash_sha1_ctx *ctx)
+{
+ BYTE hash[GIT_OID_RAWSZ];
+
+ if (!ctx->ctx.cng.updated)
+ return 0;
+
+ /* CNG needs to be finished to restart */
+ if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, hash, GIT_OID_RAWSZ, 0) < 0) {
+ git_error_set(GIT_ERROR_OS, "hash implementation could not be finished");
+ return -1;
+ }
+
+ ctx->ctx.cng.updated = 0;
+
+ return 0;
+}
+
+GIT_INLINE(int) hash_cng_update(git_hash_sha1_ctx *ctx, const void *_data, size_t len)
+{
+ PBYTE data = (PBYTE)_data;
+
+ while (len > 0) {
+ ULONG chunk = (len > ULONG_MAX) ? ULONG_MAX : (ULONG)len;
+
+ if (ctx->prov->prov.cng.hash_data(ctx->ctx.cng.hash_handle, data, chunk, 0) < 0) {
+ git_error_set(GIT_ERROR_OS, "hash could not be updated");
+ return -1;
+ }
+
+ data += chunk;
+ len -= chunk;
+ }
+
+ return 0;
+}
+
+GIT_INLINE(int) hash_cng_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ if (ctx->prov->prov.cng.finish_hash(ctx->ctx.cng.hash_handle, out->id, GIT_OID_RAWSZ, 0) < 0) {
+ git_error_set(GIT_ERROR_OS, "hash could not be finished");
+ return -1;
+ }
+
+ ctx->ctx.cng.updated = 0;
+
+ return 0;
+}
+
+GIT_INLINE(void) hash_ctx_cng_cleanup(git_hash_sha1_ctx *ctx)
+{
+ ctx->prov->prov.cng.destroy_hash(ctx->ctx.cng.hash_handle);
+ git__free(ctx->ctx.cng.hash_object);
+}
+
+/* Indirection between CryptoAPI and CNG */
+
+int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx)
+{
+ int error = 0;
+
+ assert(ctx);
+
+ /*
+ * When compiled with GIT_THREADS, the global hash_prov data is
+ * initialized with git_libgit2_init. Otherwise, it must be initialized
+ * at first use.
+ */
+ if (hash_prov.type == INVALID && (error = git_hash_sha1_global_init()) < 0)
+ return error;
+
+ memset(ctx, 0x0, sizeof(git_hash_sha1_ctx));
+
+ return (hash_prov.type == CNG) ? hash_ctx_cng_init(ctx) : hash_ctx_cryptoapi_init(ctx);
+}
+
+int git_hash_sha1_init(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx && ctx->type);
+ return (ctx->type == CNG) ? hash_cng_init(ctx) : hash_cryptoapi_init(ctx);
+}
+
+int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len)
+{
+ assert(ctx && ctx->type);
+ return (ctx->type == CNG) ? hash_cng_update(ctx, data, len) : hash_cryptoapi_update(ctx, data, len);
+}
+
+int git_hash_sha1_final(git_oid *out, git_hash_sha1_ctx *ctx)
+{
+ assert(ctx && ctx->type);
+ return (ctx->type == CNG) ? hash_cng_final(out, ctx) : hash_cryptoapi_final(out, ctx);
+}
+
+void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx)
+{
+ assert(ctx);
+
+ if (ctx->type == CNG)
+ hash_ctx_cng_cleanup(ctx);
+ else if(ctx->type == CRYPTOAPI)
+ hash_ctx_cryptoapi_cleanup(ctx);
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_hash_sha1_win32_h__
+#define INCLUDE_hash_sha1_win32_h__
+
+#include "hash/sha1.h"
+
+#include <wincrypt.h>
+#include <strsafe.h>
+
+enum hash_win32_prov_type {
+ INVALID = 0,
+ CRYPTOAPI,
+ CNG
+};
+
+/*
+ * CryptoAPI is available for hashing on Windows XP and newer.
+ */
+
+struct hash_cryptoapi_prov {
+ HCRYPTPROV handle;
+};
+
+/*
+ * CNG (bcrypt.dll) is significantly more performant than CryptoAPI and is
+ * preferred, however it is only available on Windows 2008 and newer and
+ * must therefore be dynamically loaded, and we must inline constants that
+ * would not exist when building in pre-Windows 2008 environments.
+ */
+
+/* Function declarations for CNG */
+typedef NTSTATUS (WINAPI *hash_win32_cng_open_algorithm_provider_fn)(
+ HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm,
+ LPCWSTR pszAlgId,
+ LPCWSTR pszImplementation,
+ DWORD dwFlags);
+
+typedef NTSTATUS (WINAPI *hash_win32_cng_get_property_fn)(
+ HANDLE /* BCRYPT_HANDLE */ hObject,
+ LPCWSTR pszProperty,
+ PUCHAR pbOutput,
+ ULONG cbOutput,
+ ULONG *pcbResult,
+ ULONG dwFlags);
+
+typedef NTSTATUS (WINAPI *hash_win32_cng_create_hash_fn)(
+ HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm,
+ HANDLE /* BCRYPT_HASH_HANDLE */ *phHash,
+ PUCHAR pbHashObject, ULONG cbHashObject,
+ PUCHAR pbSecret,
+ ULONG cbSecret,
+ ULONG dwFlags);
+
+typedef NTSTATUS (WINAPI *hash_win32_cng_finish_hash_fn)(
+ HANDLE /* BCRYPT_HASH_HANDLE */ hHash,
+ PUCHAR pbOutput,
+ ULONG cbOutput,
+ ULONG dwFlags);
+
+typedef NTSTATUS (WINAPI *hash_win32_cng_hash_data_fn)(
+ HANDLE /* BCRYPT_HASH_HANDLE */ hHash,
+ PUCHAR pbInput,
+ ULONG cbInput,
+ ULONG dwFlags);
+
+typedef NTSTATUS (WINAPI *hash_win32_cng_destroy_hash_fn)(
+ HANDLE /* BCRYPT_HASH_HANDLE */ hHash);
+
+typedef NTSTATUS (WINAPI *hash_win32_cng_close_algorithm_provider_fn)(
+ HANDLE /* BCRYPT_ALG_HANDLE */ hAlgorithm,
+ ULONG dwFlags);
+
+struct hash_cng_prov {
+ /* DLL for CNG */
+ HINSTANCE dll;
+
+ /* Function pointers for CNG */
+ hash_win32_cng_open_algorithm_provider_fn open_algorithm_provider;
+ hash_win32_cng_get_property_fn get_property;
+ hash_win32_cng_create_hash_fn create_hash;
+ hash_win32_cng_finish_hash_fn finish_hash;
+ hash_win32_cng_hash_data_fn hash_data;
+ hash_win32_cng_destroy_hash_fn destroy_hash;
+ hash_win32_cng_close_algorithm_provider_fn close_algorithm_provider;
+
+ HANDLE /* BCRYPT_ALG_HANDLE */ handle;
+ DWORD hash_object_size;
+};
+
+typedef struct {
+ enum hash_win32_prov_type type;
+
+ union {
+ struct hash_cryptoapi_prov cryptoapi;
+ struct hash_cng_prov cng;
+ } prov;
+} git_hash_prov;
+
+/* Hash contexts */
+
+struct hash_cryptoapi_ctx {
+ bool valid;
+ HCRYPTHASH hash_handle;
+};
+
+struct hash_cng_ctx {
+ bool updated;
+ HANDLE /* BCRYPT_HASH_HANDLE */ hash_handle;
+ PBYTE hash_object;
+};
+
+struct git_hash_sha1_ctx {
+ enum hash_win32_prov_type type;
+ git_hash_prov *prov;
+
+ union {
+ struct hash_cryptoapi_ctx cryptoapi;
+ struct hash_cng_ctx cng;
+ } ctx;
+};
+
+#endif
+++ /dev/null
-/***
-* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow (danshu@microsoft.com)
-* Distributed under the MIT Software License.
-* See accompanying file LICENSE.txt or copy at
-* https://opensource.org/licenses/MIT
-***/
-
-#ifndef SHA1DC_NO_STANDARD_INCLUDES
-#include <string.h>
-#include <memory.h>
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef __unix__
-#include <sys/types.h> /* make sure macros like _BIG_ENDIAN visible */
-#endif
-#endif
-
-#ifdef SHA1DC_CUSTOM_INCLUDE_SHA1_C
-#include SHA1DC_CUSTOM_INCLUDE_SHA1_C
-#endif
-
-#ifndef SHA1DC_INIT_SAFE_HASH_DEFAULT
-#define SHA1DC_INIT_SAFE_HASH_DEFAULT 1
-#endif
-
-#include "sha1.h"
-#include "ubc_check.h"
-
-#if (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
- defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || \
- defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || \
- defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || \
- defined(__386) || defined(_M_X64) || defined(_M_AMD64))
-#define SHA1DC_ON_INTEL_LIKE_PROCESSOR
-#endif
-
-/*
- Because Little-Endian architectures are most common,
- we only set SHA1DC_BIGENDIAN if one of these conditions is met.
- Note that all MSFT platforms are little endian,
- so none of these will be defined under the MSC compiler.
- If you are compiling on a big endian platform and your compiler does not define one of these,
- you will have to add whatever macros your tool chain defines to indicate Big-Endianness.
- */
-
-#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
-/*
- * Should detect Big Endian under GCC since at least 4.6.0 (gcc svn
- * rev #165881). See
- * https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
- *
- * This also works under clang since 3.2, it copied the GCC-ism. See
- * clang.git's 3b198a97d2 ("Preprocessor: add __BYTE_ORDER__
- * predefined macro", 2012-07-27)
- */
-#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#define SHA1DC_BIGENDIAN
-#endif
-
-/* Not under GCC-alike */
-#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN)
-/*
- * Should detect Big Endian under glibc.git since 14245eb70e ("entered
- * into RCS", 1992-11-25). Defined in <endian.h> which will have been
- * brought in by standard headers. See glibc.git and
- * https://sourceforge.net/p/predef/wiki/Endianness/
- */
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define SHA1DC_BIGENDIAN
-#endif
-
-/* Not under GCC-alike or glibc */
-#elif defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
-/*
- * *BSD and newlib (embeded linux, cygwin, etc).
- * the defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN) part prevents
- * this condition from matching with Solaris/sparc.
- * (Solaris defines only one endian macro)
- */
-#if _BYTE_ORDER == _BIG_ENDIAN
-#define SHA1DC_BIGENDIAN
-#endif
-
-/* Not under GCC-alike or glibc or *BSD or newlib */
-#elif (defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
- defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || \
- defined(__sparc))
-/*
- * Should define Big Endian for a whitelist of known processors. See
- * https://sourceforge.net/p/predef/wiki/Endianness/ and
- * http://www.oracle.com/technetwork/server-storage/solaris/portingtosolaris-138514.html
- */
-#define SHA1DC_BIGENDIAN
-
-/* Not under GCC-alike or glibc or *BSD or newlib or <processor whitelist> */
-#elif defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR)
-/*
- * As a last resort before we do anything else we're not 100% sure
- * about below, we blacklist specific processors here. We could add
- * more, see e.g. https://wiki.debian.org/ArchitectureSpecificsMemo
- */
-#else /* Not under GCC-alike or glibc or *BSD or newlib or <processor whitelist> or <processor blacklist> */
-
-/* We do nothing more here for now */
-/*#error "Uncomment this to see if you fall through all the detection"*/
-
-#endif /* Big Endian detection */
-
-#if (defined(SHA1DC_FORCE_LITTLEENDIAN) && defined(SHA1DC_BIGENDIAN))
-#undef SHA1DC_BIGENDIAN
-#endif
-#if (defined(SHA1DC_FORCE_BIGENDIAN) && !defined(SHA1DC_BIGENDIAN))
-#define SHA1DC_BIGENDIAN
-#endif
-/*ENDIANNESS SELECTION*/
-
-#if defined(SHA1DC_FORCE_UNALIGNED_ACCESS) || defined(SHA1DC_ON_INTEL_LIKE_PROCESSOR)
-#define SHA1DC_ALLOW_UNALIGNED_ACCESS
-#endif /*UNALIGNMENT DETECTION*/
-
-
-#define rotate_right(x,n) (((x)>>(n))|((x)<<(32-(n))))
-#define rotate_left(x,n) (((x)<<(n))|((x)>>(32-(n))))
-
-#define sha1_bswap32(x) \
- {x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0xFF00FF); x = (x << 16) | (x >> 16);}
-
-#define sha1_mix(W, t) (rotate_left(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1))
-
-#ifdef SHA1DC_BIGENDIAN
- #define sha1_load(m, t, temp) { temp = m[t]; }
-#else
- #define sha1_load(m, t, temp) { temp = m[t]; sha1_bswap32(temp); }
-#endif
-
-#define sha1_store(W, t, x) *(volatile uint32_t *)&W[t] = x
-
-#define sha1_f1(b,c,d) ((d)^((b)&((c)^(d))))
-#define sha1_f2(b,c,d) ((b)^(c)^(d))
-#define sha1_f3(b,c,d) (((b)&(c))+((d)&((b)^(c))))
-#define sha1_f4(b,c,d) ((b)^(c)^(d))
-
-#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, m, t) \
- { e += rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; b = rotate_left(b, 30); }
-#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, m, t) \
- { e += rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; b = rotate_left(b, 30); }
-#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, m, t) \
- { e += rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; b = rotate_left(b, 30); }
-#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, m, t) \
- { e += rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; b = rotate_left(b, 30); }
-
-#define HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, m, t) \
- { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999 + m[t]; }
-#define HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, m, t) \
- { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1 + m[t]; }
-#define HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, m, t) \
- { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC + m[t]; }
-#define HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, m, t) \
- { b = rotate_right(b, 30); e -= rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6 + m[t]; }
-
-#define SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, t, temp) \
- {sha1_load(m, t, temp); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30);}
-
-#define SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(a, b, c, d, e, W, t, temp) \
- {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f1(b,c,d) + 0x5A827999; b = rotate_left(b, 30); }
-
-#define SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, t, temp) \
- {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f2(b,c,d) + 0x6ED9EBA1; b = rotate_left(b, 30); }
-
-#define SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, t, temp) \
- {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f3(b,c,d) + 0x8F1BBCDC; b = rotate_left(b, 30); }
-
-#define SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, t, temp) \
- {temp = sha1_mix(W, t); sha1_store(W, t, temp); e += temp + rotate_left(a, 5) + sha1_f4(b,c,d) + 0xCA62C1D6; b = rotate_left(b, 30); }
-
-
-#define SHA1_STORE_STATE(i) states[i][0] = a; states[i][1] = b; states[i][2] = c; states[i][3] = d; states[i][4] = e;
-
-#ifdef BUILDNOCOLLDETECTSHA1COMPRESSION
-void sha1_compression(uint32_t ihv[5], const uint32_t m[16])
-{
- uint32_t W[80];
- uint32_t a,b,c,d,e;
- unsigned i;
-
- memcpy(W, m, 16 * 4);
- for (i = 16; i < 80; ++i)
- W[i] = sha1_mix(W, i);
-
- a = ihv[0]; b = ihv[1]; c = ihv[2]; d = ihv[3]; e = ihv[4];
-
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19);
-
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39);
-
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59);
-
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79);
-
- ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
-}
-#endif /*BUILDNOCOLLDETECTSHA1COMPRESSION*/
-
-
-static void sha1_compression_W(uint32_t ihv[5], const uint32_t W[80])
-{
- uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4];
-
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 0);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 1);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 2);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 3);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 4);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 5);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 6);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 7);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 8);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 9);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 10);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 11);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 12);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 13);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 14);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, W, 15);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, W, 16);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, W, 17);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, W, 18);
- HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, W, 19);
-
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 20);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 21);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 22);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 23);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 24);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 25);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 26);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 27);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 28);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 29);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 30);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 31);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 32);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 33);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 34);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, W, 35);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, W, 36);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, W, 37);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, W, 38);
- HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, W, 39);
-
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 40);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 41);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 42);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 43);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 44);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 45);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 46);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 47);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 48);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 49);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 50);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 51);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 52);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 53);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 54);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, W, 55);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, W, 56);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, W, 57);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, W, 58);
- HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, W, 59);
-
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 60);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 61);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 62);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 63);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 64);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 65);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 66);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 67);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 68);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 69);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 70);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 71);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 72);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 73);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 74);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, W, 75);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, W, 76);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, W, 77);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, W, 78);
- HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, W, 79);
-
- ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
-}
-
-
-
-void sha1_compression_states(uint32_t ihv[5], const uint32_t m[16], uint32_t W[80], uint32_t states[80][5])
-{
- uint32_t a = ihv[0], b = ihv[1], c = ihv[2], d = ihv[3], e = ihv[4];
- uint32_t temp;
-
-#ifdef DOSTORESTATE00
- SHA1_STORE_STATE(0)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 0, temp);
-
-#ifdef DOSTORESTATE01
- SHA1_STORE_STATE(1)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 1, temp);
-
-#ifdef DOSTORESTATE02
- SHA1_STORE_STATE(2)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 2, temp);
-
-#ifdef DOSTORESTATE03
- SHA1_STORE_STATE(3)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 3, temp);
-
-#ifdef DOSTORESTATE04
- SHA1_STORE_STATE(4)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 4, temp);
-
-#ifdef DOSTORESTATE05
- SHA1_STORE_STATE(5)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 5, temp);
-
-#ifdef DOSTORESTATE06
- SHA1_STORE_STATE(6)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 6, temp);
-
-#ifdef DOSTORESTATE07
- SHA1_STORE_STATE(7)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 7, temp);
-
-#ifdef DOSTORESTATE08
- SHA1_STORE_STATE(8)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 8, temp);
-
-#ifdef DOSTORESTATE09
- SHA1_STORE_STATE(9)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 9, temp);
-
-#ifdef DOSTORESTATE10
- SHA1_STORE_STATE(10)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 10, temp);
-
-#ifdef DOSTORESTATE11
- SHA1_STORE_STATE(11)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(e, a, b, c, d, m, W, 11, temp);
-
-#ifdef DOSTORESTATE12
- SHA1_STORE_STATE(12)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(d, e, a, b, c, m, W, 12, temp);
-
-#ifdef DOSTORESTATE13
- SHA1_STORE_STATE(13)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(c, d, e, a, b, m, W, 13, temp);
-
-#ifdef DOSTORESTATE14
- SHA1_STORE_STATE(14)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(b, c, d, e, a, m, W, 14, temp);
-
-#ifdef DOSTORESTATE15
- SHA1_STORE_STATE(15)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_LOAD(a, b, c, d, e, m, W, 15, temp);
-
-#ifdef DOSTORESTATE16
- SHA1_STORE_STATE(16)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(e, a, b, c, d, W, 16, temp);
-
-#ifdef DOSTORESTATE17
- SHA1_STORE_STATE(17)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(d, e, a, b, c, W, 17, temp);
-
-#ifdef DOSTORESTATE18
- SHA1_STORE_STATE(18)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(c, d, e, a, b, W, 18, temp);
-
-#ifdef DOSTORESTATE19
- SHA1_STORE_STATE(19)
-#endif
- SHA1COMPRESS_FULL_ROUND1_STEP_EXPAND(b, c, d, e, a, W, 19, temp);
-
-
-
-#ifdef DOSTORESTATE20
- SHA1_STORE_STATE(20)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 20, temp);
-
-#ifdef DOSTORESTATE21
- SHA1_STORE_STATE(21)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 21, temp);
-
-#ifdef DOSTORESTATE22
- SHA1_STORE_STATE(22)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 22, temp);
-
-#ifdef DOSTORESTATE23
- SHA1_STORE_STATE(23)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 23, temp);
-
-#ifdef DOSTORESTATE24
- SHA1_STORE_STATE(24)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 24, temp);
-
-#ifdef DOSTORESTATE25
- SHA1_STORE_STATE(25)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 25, temp);
-
-#ifdef DOSTORESTATE26
- SHA1_STORE_STATE(26)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 26, temp);
-
-#ifdef DOSTORESTATE27
- SHA1_STORE_STATE(27)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 27, temp);
-
-#ifdef DOSTORESTATE28
- SHA1_STORE_STATE(28)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 28, temp);
-
-#ifdef DOSTORESTATE29
- SHA1_STORE_STATE(29)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 29, temp);
-
-#ifdef DOSTORESTATE30
- SHA1_STORE_STATE(30)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 30, temp);
-
-#ifdef DOSTORESTATE31
- SHA1_STORE_STATE(31)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 31, temp);
-
-#ifdef DOSTORESTATE32
- SHA1_STORE_STATE(32)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 32, temp);
-
-#ifdef DOSTORESTATE33
- SHA1_STORE_STATE(33)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 33, temp);
-
-#ifdef DOSTORESTATE34
- SHA1_STORE_STATE(34)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 34, temp);
-
-#ifdef DOSTORESTATE35
- SHA1_STORE_STATE(35)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(a, b, c, d, e, W, 35, temp);
-
-#ifdef DOSTORESTATE36
- SHA1_STORE_STATE(36)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(e, a, b, c, d, W, 36, temp);
-
-#ifdef DOSTORESTATE37
- SHA1_STORE_STATE(37)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(d, e, a, b, c, W, 37, temp);
-
-#ifdef DOSTORESTATE38
- SHA1_STORE_STATE(38)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(c, d, e, a, b, W, 38, temp);
-
-#ifdef DOSTORESTATE39
- SHA1_STORE_STATE(39)
-#endif
- SHA1COMPRESS_FULL_ROUND2_STEP(b, c, d, e, a, W, 39, temp);
-
-
-
-#ifdef DOSTORESTATE40
- SHA1_STORE_STATE(40)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 40, temp);
-
-#ifdef DOSTORESTATE41
- SHA1_STORE_STATE(41)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 41, temp);
-
-#ifdef DOSTORESTATE42
- SHA1_STORE_STATE(42)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 42, temp);
-
-#ifdef DOSTORESTATE43
- SHA1_STORE_STATE(43)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 43, temp);
-
-#ifdef DOSTORESTATE44
- SHA1_STORE_STATE(44)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 44, temp);
-
-#ifdef DOSTORESTATE45
- SHA1_STORE_STATE(45)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 45, temp);
-
-#ifdef DOSTORESTATE46
- SHA1_STORE_STATE(46)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 46, temp);
-
-#ifdef DOSTORESTATE47
- SHA1_STORE_STATE(47)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 47, temp);
-
-#ifdef DOSTORESTATE48
- SHA1_STORE_STATE(48)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 48, temp);
-
-#ifdef DOSTORESTATE49
- SHA1_STORE_STATE(49)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 49, temp);
-
-#ifdef DOSTORESTATE50
- SHA1_STORE_STATE(50)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 50, temp);
-
-#ifdef DOSTORESTATE51
- SHA1_STORE_STATE(51)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 51, temp);
-
-#ifdef DOSTORESTATE52
- SHA1_STORE_STATE(52)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 52, temp);
-
-#ifdef DOSTORESTATE53
- SHA1_STORE_STATE(53)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 53, temp);
-
-#ifdef DOSTORESTATE54
- SHA1_STORE_STATE(54)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 54, temp);
-
-#ifdef DOSTORESTATE55
- SHA1_STORE_STATE(55)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(a, b, c, d, e, W, 55, temp);
-
-#ifdef DOSTORESTATE56
- SHA1_STORE_STATE(56)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(e, a, b, c, d, W, 56, temp);
-
-#ifdef DOSTORESTATE57
- SHA1_STORE_STATE(57)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(d, e, a, b, c, W, 57, temp);
-
-#ifdef DOSTORESTATE58
- SHA1_STORE_STATE(58)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(c, d, e, a, b, W, 58, temp);
-
-#ifdef DOSTORESTATE59
- SHA1_STORE_STATE(59)
-#endif
- SHA1COMPRESS_FULL_ROUND3_STEP(b, c, d, e, a, W, 59, temp);
-
-
-
-
-#ifdef DOSTORESTATE60
- SHA1_STORE_STATE(60)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 60, temp);
-
-#ifdef DOSTORESTATE61
- SHA1_STORE_STATE(61)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 61, temp);
-
-#ifdef DOSTORESTATE62
- SHA1_STORE_STATE(62)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 62, temp);
-
-#ifdef DOSTORESTATE63
- SHA1_STORE_STATE(63)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 63, temp);
-
-#ifdef DOSTORESTATE64
- SHA1_STORE_STATE(64)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 64, temp);
-
-#ifdef DOSTORESTATE65
- SHA1_STORE_STATE(65)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 65, temp);
-
-#ifdef DOSTORESTATE66
- SHA1_STORE_STATE(66)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 66, temp);
-
-#ifdef DOSTORESTATE67
- SHA1_STORE_STATE(67)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 67, temp);
-
-#ifdef DOSTORESTATE68
- SHA1_STORE_STATE(68)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 68, temp);
-
-#ifdef DOSTORESTATE69
- SHA1_STORE_STATE(69)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 69, temp);
-
-#ifdef DOSTORESTATE70
- SHA1_STORE_STATE(70)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 70, temp);
-
-#ifdef DOSTORESTATE71
- SHA1_STORE_STATE(71)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 71, temp);
-
-#ifdef DOSTORESTATE72
- SHA1_STORE_STATE(72)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 72, temp);
-
-#ifdef DOSTORESTATE73
- SHA1_STORE_STATE(73)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 73, temp);
-
-#ifdef DOSTORESTATE74
- SHA1_STORE_STATE(74)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 74, temp);
-
-#ifdef DOSTORESTATE75
- SHA1_STORE_STATE(75)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(a, b, c, d, e, W, 75, temp);
-
-#ifdef DOSTORESTATE76
- SHA1_STORE_STATE(76)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(e, a, b, c, d, W, 76, temp);
-
-#ifdef DOSTORESTATE77
- SHA1_STORE_STATE(77)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(d, e, a, b, c, W, 77, temp);
-
-#ifdef DOSTORESTATE78
- SHA1_STORE_STATE(78)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(c, d, e, a, b, W, 78, temp);
-
-#ifdef DOSTORESTATE79
- SHA1_STORE_STATE(79)
-#endif
- SHA1COMPRESS_FULL_ROUND4_STEP(b, c, d, e, a, W, 79, temp);
-
-
-
- ihv[0] += a; ihv[1] += b; ihv[2] += c; ihv[3] += d; ihv[4] += e;
-}
-
-
-
-
-#define SHA1_RECOMPRESS(t) \
-static void sha1recompress_fast_ ## t (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]) \
-{ \
- uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; \
- if (t > 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 79); \
- if (t > 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 78); \
- if (t > 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 77); \
- if (t > 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 76); \
- if (t > 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 75); \
- if (t > 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 74); \
- if (t > 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 73); \
- if (t > 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 72); \
- if (t > 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 71); \
- if (t > 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 70); \
- if (t > 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 69); \
- if (t > 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 68); \
- if (t > 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 67); \
- if (t > 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 66); \
- if (t > 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 65); \
- if (t > 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(b, c, d, e, a, me2, 64); \
- if (t > 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(c, d, e, a, b, me2, 63); \
- if (t > 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(d, e, a, b, c, me2, 62); \
- if (t > 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(e, a, b, c, d, me2, 61); \
- if (t > 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP_BW(a, b, c, d, e, me2, 60); \
- if (t > 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 59); \
- if (t > 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 58); \
- if (t > 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 57); \
- if (t > 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 56); \
- if (t > 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 55); \
- if (t > 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 54); \
- if (t > 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 53); \
- if (t > 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 52); \
- if (t > 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 51); \
- if (t > 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 50); \
- if (t > 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 49); \
- if (t > 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 48); \
- if (t > 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 47); \
- if (t > 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 46); \
- if (t > 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 45); \
- if (t > 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(b, c, d, e, a, me2, 44); \
- if (t > 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(c, d, e, a, b, me2, 43); \
- if (t > 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(d, e, a, b, c, me2, 42); \
- if (t > 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(e, a, b, c, d, me2, 41); \
- if (t > 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP_BW(a, b, c, d, e, me2, 40); \
- if (t > 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 39); \
- if (t > 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 38); \
- if (t > 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 37); \
- if (t > 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 36); \
- if (t > 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 35); \
- if (t > 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 34); \
- if (t > 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 33); \
- if (t > 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 32); \
- if (t > 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 31); \
- if (t > 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 30); \
- if (t > 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 29); \
- if (t > 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 28); \
- if (t > 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 27); \
- if (t > 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 26); \
- if (t > 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 25); \
- if (t > 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(b, c, d, e, a, me2, 24); \
- if (t > 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(c, d, e, a, b, me2, 23); \
- if (t > 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(d, e, a, b, c, me2, 22); \
- if (t > 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(e, a, b, c, d, me2, 21); \
- if (t > 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP_BW(a, b, c, d, e, me2, 20); \
- if (t > 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 19); \
- if (t > 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 18); \
- if (t > 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 17); \
- if (t > 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 16); \
- if (t > 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 15); \
- if (t > 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 14); \
- if (t > 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 13); \
- if (t > 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 12); \
- if (t > 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 11); \
- if (t > 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 10); \
- if (t > 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 9); \
- if (t > 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 8); \
- if (t > 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 7); \
- if (t > 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 6); \
- if (t > 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 5); \
- if (t > 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(b, c, d, e, a, me2, 4); \
- if (t > 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(c, d, e, a, b, me2, 3); \
- if (t > 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(d, e, a, b, c, me2, 2); \
- if (t > 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(e, a, b, c, d, me2, 1); \
- if (t > 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP_BW(a, b, c, d, e, me2, 0); \
- ihvin[0] = a; ihvin[1] = b; ihvin[2] = c; ihvin[3] = d; ihvin[4] = e; \
- a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; \
- if (t <= 0) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 0); \
- if (t <= 1) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 1); \
- if (t <= 2) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 2); \
- if (t <= 3) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 3); \
- if (t <= 4) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 4); \
- if (t <= 5) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 5); \
- if (t <= 6) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 6); \
- if (t <= 7) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 7); \
- if (t <= 8) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 8); \
- if (t <= 9) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 9); \
- if (t <= 10) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 10); \
- if (t <= 11) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 11); \
- if (t <= 12) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 12); \
- if (t <= 13) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 13); \
- if (t <= 14) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 14); \
- if (t <= 15) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(a, b, c, d, e, me2, 15); \
- if (t <= 16) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(e, a, b, c, d, me2, 16); \
- if (t <= 17) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(d, e, a, b, c, me2, 17); \
- if (t <= 18) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(c, d, e, a, b, me2, 18); \
- if (t <= 19) HASHCLASH_SHA1COMPRESS_ROUND1_STEP(b, c, d, e, a, me2, 19); \
- if (t <= 20) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 20); \
- if (t <= 21) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 21); \
- if (t <= 22) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 22); \
- if (t <= 23) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 23); \
- if (t <= 24) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 24); \
- if (t <= 25) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 25); \
- if (t <= 26) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 26); \
- if (t <= 27) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 27); \
- if (t <= 28) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 28); \
- if (t <= 29) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 29); \
- if (t <= 30) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 30); \
- if (t <= 31) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 31); \
- if (t <= 32) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 32); \
- if (t <= 33) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 33); \
- if (t <= 34) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 34); \
- if (t <= 35) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(a, b, c, d, e, me2, 35); \
- if (t <= 36) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(e, a, b, c, d, me2, 36); \
- if (t <= 37) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(d, e, a, b, c, me2, 37); \
- if (t <= 38) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(c, d, e, a, b, me2, 38); \
- if (t <= 39) HASHCLASH_SHA1COMPRESS_ROUND2_STEP(b, c, d, e, a, me2, 39); \
- if (t <= 40) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 40); \
- if (t <= 41) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 41); \
- if (t <= 42) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 42); \
- if (t <= 43) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 43); \
- if (t <= 44) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 44); \
- if (t <= 45) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 45); \
- if (t <= 46) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 46); \
- if (t <= 47) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 47); \
- if (t <= 48) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 48); \
- if (t <= 49) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 49); \
- if (t <= 50) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 50); \
- if (t <= 51) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 51); \
- if (t <= 52) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 52); \
- if (t <= 53) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 53); \
- if (t <= 54) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 54); \
- if (t <= 55) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(a, b, c, d, e, me2, 55); \
- if (t <= 56) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(e, a, b, c, d, me2, 56); \
- if (t <= 57) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(d, e, a, b, c, me2, 57); \
- if (t <= 58) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(c, d, e, a, b, me2, 58); \
- if (t <= 59) HASHCLASH_SHA1COMPRESS_ROUND3_STEP(b, c, d, e, a, me2, 59); \
- if (t <= 60) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 60); \
- if (t <= 61) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 61); \
- if (t <= 62) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 62); \
- if (t <= 63) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 63); \
- if (t <= 64) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 64); \
- if (t <= 65) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 65); \
- if (t <= 66) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 66); \
- if (t <= 67) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 67); \
- if (t <= 68) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 68); \
- if (t <= 69) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 69); \
- if (t <= 70) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 70); \
- if (t <= 71) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 71); \
- if (t <= 72) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 72); \
- if (t <= 73) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 73); \
- if (t <= 74) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 74); \
- if (t <= 75) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(a, b, c, d, e, me2, 75); \
- if (t <= 76) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(e, a, b, c, d, me2, 76); \
- if (t <= 77) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(d, e, a, b, c, me2, 77); \
- if (t <= 78) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(c, d, e, a, b, me2, 78); \
- if (t <= 79) HASHCLASH_SHA1COMPRESS_ROUND4_STEP(b, c, d, e, a, me2, 79); \
- ihvout[0] = ihvin[0] + a; ihvout[1] = ihvin[1] + b; ihvout[2] = ihvin[2] + c; ihvout[3] = ihvin[3] + d; ihvout[4] = ihvin[4] + e; \
-}
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4127) /* Compiler complains about the checks in the above macro being constant. */
-#endif
-
-#ifdef DOSTORESTATE0
-SHA1_RECOMPRESS(0)
-#endif
-
-#ifdef DOSTORESTATE1
-SHA1_RECOMPRESS(1)
-#endif
-
-#ifdef DOSTORESTATE2
-SHA1_RECOMPRESS(2)
-#endif
-
-#ifdef DOSTORESTATE3
-SHA1_RECOMPRESS(3)
-#endif
-
-#ifdef DOSTORESTATE4
-SHA1_RECOMPRESS(4)
-#endif
-
-#ifdef DOSTORESTATE5
-SHA1_RECOMPRESS(5)
-#endif
-
-#ifdef DOSTORESTATE6
-SHA1_RECOMPRESS(6)
-#endif
-
-#ifdef DOSTORESTATE7
-SHA1_RECOMPRESS(7)
-#endif
-
-#ifdef DOSTORESTATE8
-SHA1_RECOMPRESS(8)
-#endif
-
-#ifdef DOSTORESTATE9
-SHA1_RECOMPRESS(9)
-#endif
-
-#ifdef DOSTORESTATE10
-SHA1_RECOMPRESS(10)
-#endif
-
-#ifdef DOSTORESTATE11
-SHA1_RECOMPRESS(11)
-#endif
-
-#ifdef DOSTORESTATE12
-SHA1_RECOMPRESS(12)
-#endif
-
-#ifdef DOSTORESTATE13
-SHA1_RECOMPRESS(13)
-#endif
-
-#ifdef DOSTORESTATE14
-SHA1_RECOMPRESS(14)
-#endif
-
-#ifdef DOSTORESTATE15
-SHA1_RECOMPRESS(15)
-#endif
-
-#ifdef DOSTORESTATE16
-SHA1_RECOMPRESS(16)
-#endif
-
-#ifdef DOSTORESTATE17
-SHA1_RECOMPRESS(17)
-#endif
-
-#ifdef DOSTORESTATE18
-SHA1_RECOMPRESS(18)
-#endif
-
-#ifdef DOSTORESTATE19
-SHA1_RECOMPRESS(19)
-#endif
-
-#ifdef DOSTORESTATE20
-SHA1_RECOMPRESS(20)
-#endif
-
-#ifdef DOSTORESTATE21
-SHA1_RECOMPRESS(21)
-#endif
-
-#ifdef DOSTORESTATE22
-SHA1_RECOMPRESS(22)
-#endif
-
-#ifdef DOSTORESTATE23
-SHA1_RECOMPRESS(23)
-#endif
-
-#ifdef DOSTORESTATE24
-SHA1_RECOMPRESS(24)
-#endif
-
-#ifdef DOSTORESTATE25
-SHA1_RECOMPRESS(25)
-#endif
-
-#ifdef DOSTORESTATE26
-SHA1_RECOMPRESS(26)
-#endif
-
-#ifdef DOSTORESTATE27
-SHA1_RECOMPRESS(27)
-#endif
-
-#ifdef DOSTORESTATE28
-SHA1_RECOMPRESS(28)
-#endif
-
-#ifdef DOSTORESTATE29
-SHA1_RECOMPRESS(29)
-#endif
-
-#ifdef DOSTORESTATE30
-SHA1_RECOMPRESS(30)
-#endif
-
-#ifdef DOSTORESTATE31
-SHA1_RECOMPRESS(31)
-#endif
-
-#ifdef DOSTORESTATE32
-SHA1_RECOMPRESS(32)
-#endif
-
-#ifdef DOSTORESTATE33
-SHA1_RECOMPRESS(33)
-#endif
-
-#ifdef DOSTORESTATE34
-SHA1_RECOMPRESS(34)
-#endif
-
-#ifdef DOSTORESTATE35
-SHA1_RECOMPRESS(35)
-#endif
-
-#ifdef DOSTORESTATE36
-SHA1_RECOMPRESS(36)
-#endif
-
-#ifdef DOSTORESTATE37
-SHA1_RECOMPRESS(37)
-#endif
-
-#ifdef DOSTORESTATE38
-SHA1_RECOMPRESS(38)
-#endif
-
-#ifdef DOSTORESTATE39
-SHA1_RECOMPRESS(39)
-#endif
-
-#ifdef DOSTORESTATE40
-SHA1_RECOMPRESS(40)
-#endif
-
-#ifdef DOSTORESTATE41
-SHA1_RECOMPRESS(41)
-#endif
-
-#ifdef DOSTORESTATE42
-SHA1_RECOMPRESS(42)
-#endif
-
-#ifdef DOSTORESTATE43
-SHA1_RECOMPRESS(43)
-#endif
-
-#ifdef DOSTORESTATE44
-SHA1_RECOMPRESS(44)
-#endif
-
-#ifdef DOSTORESTATE45
-SHA1_RECOMPRESS(45)
-#endif
-
-#ifdef DOSTORESTATE46
-SHA1_RECOMPRESS(46)
-#endif
-
-#ifdef DOSTORESTATE47
-SHA1_RECOMPRESS(47)
-#endif
-
-#ifdef DOSTORESTATE48
-SHA1_RECOMPRESS(48)
-#endif
-
-#ifdef DOSTORESTATE49
-SHA1_RECOMPRESS(49)
-#endif
-
-#ifdef DOSTORESTATE50
-SHA1_RECOMPRESS(50)
-#endif
-
-#ifdef DOSTORESTATE51
-SHA1_RECOMPRESS(51)
-#endif
-
-#ifdef DOSTORESTATE52
-SHA1_RECOMPRESS(52)
-#endif
-
-#ifdef DOSTORESTATE53
-SHA1_RECOMPRESS(53)
-#endif
-
-#ifdef DOSTORESTATE54
-SHA1_RECOMPRESS(54)
-#endif
-
-#ifdef DOSTORESTATE55
-SHA1_RECOMPRESS(55)
-#endif
-
-#ifdef DOSTORESTATE56
-SHA1_RECOMPRESS(56)
-#endif
-
-#ifdef DOSTORESTATE57
-SHA1_RECOMPRESS(57)
-#endif
-
-#ifdef DOSTORESTATE58
-SHA1_RECOMPRESS(58)
-#endif
-
-#ifdef DOSTORESTATE59
-SHA1_RECOMPRESS(59)
-#endif
-
-#ifdef DOSTORESTATE60
-SHA1_RECOMPRESS(60)
-#endif
-
-#ifdef DOSTORESTATE61
-SHA1_RECOMPRESS(61)
-#endif
-
-#ifdef DOSTORESTATE62
-SHA1_RECOMPRESS(62)
-#endif
-
-#ifdef DOSTORESTATE63
-SHA1_RECOMPRESS(63)
-#endif
-
-#ifdef DOSTORESTATE64
-SHA1_RECOMPRESS(64)
-#endif
-
-#ifdef DOSTORESTATE65
-SHA1_RECOMPRESS(65)
-#endif
-
-#ifdef DOSTORESTATE66
-SHA1_RECOMPRESS(66)
-#endif
-
-#ifdef DOSTORESTATE67
-SHA1_RECOMPRESS(67)
-#endif
-
-#ifdef DOSTORESTATE68
-SHA1_RECOMPRESS(68)
-#endif
-
-#ifdef DOSTORESTATE69
-SHA1_RECOMPRESS(69)
-#endif
-
-#ifdef DOSTORESTATE70
-SHA1_RECOMPRESS(70)
-#endif
-
-#ifdef DOSTORESTATE71
-SHA1_RECOMPRESS(71)
-#endif
-
-#ifdef DOSTORESTATE72
-SHA1_RECOMPRESS(72)
-#endif
-
-#ifdef DOSTORESTATE73
-SHA1_RECOMPRESS(73)
-#endif
-
-#ifdef DOSTORESTATE74
-SHA1_RECOMPRESS(74)
-#endif
-
-#ifdef DOSTORESTATE75
-SHA1_RECOMPRESS(75)
-#endif
-
-#ifdef DOSTORESTATE76
-SHA1_RECOMPRESS(76)
-#endif
-
-#ifdef DOSTORESTATE77
-SHA1_RECOMPRESS(77)
-#endif
-
-#ifdef DOSTORESTATE78
-SHA1_RECOMPRESS(78)
-#endif
-
-#ifdef DOSTORESTATE79
-SHA1_RECOMPRESS(79)
-#endif
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-static void sha1_recompression_step(uint32_t step, uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5])
-{
- switch (step)
- {
-#ifdef DOSTORESTATE0
- case 0:
- sha1recompress_fast_0(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE1
- case 1:
- sha1recompress_fast_1(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE2
- case 2:
- sha1recompress_fast_2(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE3
- case 3:
- sha1recompress_fast_3(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE4
- case 4:
- sha1recompress_fast_4(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE5
- case 5:
- sha1recompress_fast_5(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE6
- case 6:
- sha1recompress_fast_6(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE7
- case 7:
- sha1recompress_fast_7(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE8
- case 8:
- sha1recompress_fast_8(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE9
- case 9:
- sha1recompress_fast_9(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE10
- case 10:
- sha1recompress_fast_10(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE11
- case 11:
- sha1recompress_fast_11(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE12
- case 12:
- sha1recompress_fast_12(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE13
- case 13:
- sha1recompress_fast_13(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE14
- case 14:
- sha1recompress_fast_14(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE15
- case 15:
- sha1recompress_fast_15(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE16
- case 16:
- sha1recompress_fast_16(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE17
- case 17:
- sha1recompress_fast_17(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE18
- case 18:
- sha1recompress_fast_18(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE19
- case 19:
- sha1recompress_fast_19(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE20
- case 20:
- sha1recompress_fast_20(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE21
- case 21:
- sha1recompress_fast_21(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE22
- case 22:
- sha1recompress_fast_22(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE23
- case 23:
- sha1recompress_fast_23(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE24
- case 24:
- sha1recompress_fast_24(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE25
- case 25:
- sha1recompress_fast_25(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE26
- case 26:
- sha1recompress_fast_26(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE27
- case 27:
- sha1recompress_fast_27(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE28
- case 28:
- sha1recompress_fast_28(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE29
- case 29:
- sha1recompress_fast_29(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE30
- case 30:
- sha1recompress_fast_30(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE31
- case 31:
- sha1recompress_fast_31(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE32
- case 32:
- sha1recompress_fast_32(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE33
- case 33:
- sha1recompress_fast_33(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE34
- case 34:
- sha1recompress_fast_34(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE35
- case 35:
- sha1recompress_fast_35(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE36
- case 36:
- sha1recompress_fast_36(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE37
- case 37:
- sha1recompress_fast_37(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE38
- case 38:
- sha1recompress_fast_38(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE39
- case 39:
- sha1recompress_fast_39(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE40
- case 40:
- sha1recompress_fast_40(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE41
- case 41:
- sha1recompress_fast_41(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE42
- case 42:
- sha1recompress_fast_42(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE43
- case 43:
- sha1recompress_fast_43(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE44
- case 44:
- sha1recompress_fast_44(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE45
- case 45:
- sha1recompress_fast_45(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE46
- case 46:
- sha1recompress_fast_46(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE47
- case 47:
- sha1recompress_fast_47(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE48
- case 48:
- sha1recompress_fast_48(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE49
- case 49:
- sha1recompress_fast_49(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE50
- case 50:
- sha1recompress_fast_50(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE51
- case 51:
- sha1recompress_fast_51(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE52
- case 52:
- sha1recompress_fast_52(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE53
- case 53:
- sha1recompress_fast_53(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE54
- case 54:
- sha1recompress_fast_54(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE55
- case 55:
- sha1recompress_fast_55(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE56
- case 56:
- sha1recompress_fast_56(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE57
- case 57:
- sha1recompress_fast_57(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE58
- case 58:
- sha1recompress_fast_58(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE59
- case 59:
- sha1recompress_fast_59(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE60
- case 60:
- sha1recompress_fast_60(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE61
- case 61:
- sha1recompress_fast_61(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE62
- case 62:
- sha1recompress_fast_62(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE63
- case 63:
- sha1recompress_fast_63(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE64
- case 64:
- sha1recompress_fast_64(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE65
- case 65:
- sha1recompress_fast_65(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE66
- case 66:
- sha1recompress_fast_66(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE67
- case 67:
- sha1recompress_fast_67(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE68
- case 68:
- sha1recompress_fast_68(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE69
- case 69:
- sha1recompress_fast_69(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE70
- case 70:
- sha1recompress_fast_70(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE71
- case 71:
- sha1recompress_fast_71(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE72
- case 72:
- sha1recompress_fast_72(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE73
- case 73:
- sha1recompress_fast_73(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE74
- case 74:
- sha1recompress_fast_74(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE75
- case 75:
- sha1recompress_fast_75(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE76
- case 76:
- sha1recompress_fast_76(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE77
- case 77:
- sha1recompress_fast_77(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE78
- case 78:
- sha1recompress_fast_78(ihvin, ihvout, me2, state);
- break;
-#endif
-#ifdef DOSTORESTATE79
- case 79:
- sha1recompress_fast_79(ihvin, ihvout, me2, state);
- break;
-#endif
- default:
- abort();
- }
-
-}
-
-
-
-static void sha1_process(SHA1_CTX* ctx, const uint32_t block[16])
-{
- unsigned i, j;
- uint32_t ubc_dv_mask[DVMASKSIZE] = { 0xFFFFFFFF };
- uint32_t ihvtmp[5];
-
- ctx->ihv1[0] = ctx->ihv[0];
- ctx->ihv1[1] = ctx->ihv[1];
- ctx->ihv1[2] = ctx->ihv[2];
- ctx->ihv1[3] = ctx->ihv[3];
- ctx->ihv1[4] = ctx->ihv[4];
-
- sha1_compression_states(ctx->ihv, block, ctx->m1, ctx->states);
-
- if (ctx->detect_coll)
- {
- if (ctx->ubc_check)
- {
- ubc_check(ctx->m1, ubc_dv_mask);
- }
-
- if (ubc_dv_mask[0] != 0)
- {
- for (i = 0; sha1_dvs[i].dvType != 0; ++i)
- {
- if (ubc_dv_mask[0] & ((uint32_t)(1) << sha1_dvs[i].maskb))
- {
- for (j = 0; j < 80; ++j)
- ctx->m2[j] = ctx->m1[j] ^ sha1_dvs[i].dm[j];
-
- sha1_recompression_step(sha1_dvs[i].testt, ctx->ihv2, ihvtmp, ctx->m2, ctx->states[sha1_dvs[i].testt]);
-
- /* to verify SHA-1 collision detection code with collisions for reduced-step SHA-1 */
- if ((0 == ((ihvtmp[0] ^ ctx->ihv[0]) | (ihvtmp[1] ^ ctx->ihv[1]) | (ihvtmp[2] ^ ctx->ihv[2]) | (ihvtmp[3] ^ ctx->ihv[3]) | (ihvtmp[4] ^ ctx->ihv[4])))
- || (ctx->reduced_round_coll && 0==((ctx->ihv1[0] ^ ctx->ihv2[0]) | (ctx->ihv1[1] ^ ctx->ihv2[1]) | (ctx->ihv1[2] ^ ctx->ihv2[2]) | (ctx->ihv1[3] ^ ctx->ihv2[3]) | (ctx->ihv1[4] ^ ctx->ihv2[4]))))
- {
- ctx->found_collision = 1;
-
- if (ctx->safe_hash)
- {
- sha1_compression_W(ctx->ihv, ctx->m1);
- sha1_compression_W(ctx->ihv, ctx->m1);
- }
-
- break;
- }
- }
- }
- }
- }
-}
-
-void SHA1DCInit(SHA1_CTX* ctx)
-{
- ctx->total = 0;
- ctx->ihv[0] = 0x67452301;
- ctx->ihv[1] = 0xEFCDAB89;
- ctx->ihv[2] = 0x98BADCFE;
- ctx->ihv[3] = 0x10325476;
- ctx->ihv[4] = 0xC3D2E1F0;
- ctx->found_collision = 0;
- ctx->safe_hash = SHA1DC_INIT_SAFE_HASH_DEFAULT;
- ctx->ubc_check = 1;
- ctx->detect_coll = 1;
- ctx->reduced_round_coll = 0;
- ctx->callback = NULL;
-}
-
-void SHA1DCSetSafeHash(SHA1_CTX* ctx, int safehash)
-{
- if (safehash)
- ctx->safe_hash = 1;
- else
- ctx->safe_hash = 0;
-}
-
-
-void SHA1DCSetUseUBC(SHA1_CTX* ctx, int ubc_check)
-{
- if (ubc_check)
- ctx->ubc_check = 1;
- else
- ctx->ubc_check = 0;
-}
-
-void SHA1DCSetUseDetectColl(SHA1_CTX* ctx, int detect_coll)
-{
- if (detect_coll)
- ctx->detect_coll = 1;
- else
- ctx->detect_coll = 0;
-}
-
-void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX* ctx, int reduced_round_coll)
-{
- if (reduced_round_coll)
- ctx->reduced_round_coll = 1;
- else
- ctx->reduced_round_coll = 0;
-}
-
-void SHA1DCSetCallback(SHA1_CTX* ctx, collision_block_callback callback)
-{
- ctx->callback = callback;
-}
-
-void SHA1DCUpdate(SHA1_CTX* ctx, const char* buf, size_t len)
-{
- unsigned left, fill;
-
- if (len == 0)
- return;
-
- left = ctx->total & 63;
- fill = 64 - left;
-
- if (left && len >= fill)
- {
- ctx->total += fill;
- memcpy(ctx->buffer + left, buf, fill);
- sha1_process(ctx, (uint32_t*)(ctx->buffer));
- buf += fill;
- len -= fill;
- left = 0;
- }
- while (len >= 64)
- {
- ctx->total += 64;
-
-#if defined(SHA1DC_ALLOW_UNALIGNED_ACCESS)
- sha1_process(ctx, (uint32_t*)(buf));
-#else
- memcpy(ctx->buffer, buf, 64);
- sha1_process(ctx, (uint32_t*)(ctx->buffer));
-#endif /* defined(SHA1DC_ALLOW_UNALIGNED_ACCESS) */
- buf += 64;
- len -= 64;
- }
- if (len > 0)
- {
- ctx->total += len;
- memcpy(ctx->buffer + left, buf, len);
- }
-}
-
-static const unsigned char sha1_padding[64] =
-{
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-int SHA1DCFinal(unsigned char output[20], SHA1_CTX *ctx)
-{
- uint32_t last = ctx->total & 63;
- uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
- uint64_t total;
- SHA1DCUpdate(ctx, (const char*)(sha1_padding), padn);
-
- total = ctx->total - padn;
- total <<= 3;
- ctx->buffer[56] = (unsigned char)(total >> 56);
- ctx->buffer[57] = (unsigned char)(total >> 48);
- ctx->buffer[58] = (unsigned char)(total >> 40);
- ctx->buffer[59] = (unsigned char)(total >> 32);
- ctx->buffer[60] = (unsigned char)(total >> 24);
- ctx->buffer[61] = (unsigned char)(total >> 16);
- ctx->buffer[62] = (unsigned char)(total >> 8);
- ctx->buffer[63] = (unsigned char)(total);
- sha1_process(ctx, (uint32_t*)(ctx->buffer));
- output[0] = (unsigned char)(ctx->ihv[0] >> 24);
- output[1] = (unsigned char)(ctx->ihv[0] >> 16);
- output[2] = (unsigned char)(ctx->ihv[0] >> 8);
- output[3] = (unsigned char)(ctx->ihv[0]);
- output[4] = (unsigned char)(ctx->ihv[1] >> 24);
- output[5] = (unsigned char)(ctx->ihv[1] >> 16);
- output[6] = (unsigned char)(ctx->ihv[1] >> 8);
- output[7] = (unsigned char)(ctx->ihv[1]);
- output[8] = (unsigned char)(ctx->ihv[2] >> 24);
- output[9] = (unsigned char)(ctx->ihv[2] >> 16);
- output[10] = (unsigned char)(ctx->ihv[2] >> 8);
- output[11] = (unsigned char)(ctx->ihv[2]);
- output[12] = (unsigned char)(ctx->ihv[3] >> 24);
- output[13] = (unsigned char)(ctx->ihv[3] >> 16);
- output[14] = (unsigned char)(ctx->ihv[3] >> 8);
- output[15] = (unsigned char)(ctx->ihv[3]);
- output[16] = (unsigned char)(ctx->ihv[4] >> 24);
- output[17] = (unsigned char)(ctx->ihv[4] >> 16);
- output[18] = (unsigned char)(ctx->ihv[4] >> 8);
- output[19] = (unsigned char)(ctx->ihv[4]);
- return ctx->found_collision;
-}
-
-#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C
-#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_C
-#endif
+++ /dev/null
-/***
-* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
-* Distributed under the MIT Software License.
-* See accompanying file LICENSE.txt or copy at
-* https://opensource.org/licenses/MIT
-***/
-
-#ifndef SHA1DC_SHA1_H
-#define SHA1DC_SHA1_H
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#ifndef SHA1DC_NO_STANDARD_INCLUDES
-#include <stdint.h>
-#endif
-
-/* sha-1 compression function that takes an already expanded message, and additionally store intermediate states */
-/* only stores states ii (the state between step ii-1 and step ii) when DOSTORESTATEii is defined in ubc_check.h */
-void sha1_compression_states(uint32_t[5], const uint32_t[16], uint32_t[80], uint32_t[80][5]);
-
-/*
-// Function type for sha1_recompression_step_T (uint32_t ihvin[5], uint32_t ihvout[5], const uint32_t me2[80], const uint32_t state[5]).
-// Where 0 <= T < 80
-// me2 is an expanded message (the expansion of an original message block XOR'ed with a disturbance vector's message block difference.)
-// state is the internal state (a,b,c,d,e) before step T of the SHA-1 compression function while processing the original message block.
-// The function will return:
-// ihvin: The reconstructed input chaining value.
-// ihvout: The reconstructed output chaining value.
-*/
-typedef void(*sha1_recompression_type)(uint32_t*, uint32_t*, const uint32_t*, const uint32_t*);
-
-/* A callback function type that can be set to be called when a collision block has been found: */
-/* void collision_block_callback(uint64_t byteoffset, const uint32_t ihvin1[5], const uint32_t ihvin2[5], const uint32_t m1[80], const uint32_t m2[80]) */
-typedef void(*collision_block_callback)(uint64_t, const uint32_t*, const uint32_t*, const uint32_t*, const uint32_t*);
-
-/* The SHA-1 context. */
-typedef struct {
- uint64_t total;
- uint32_t ihv[5];
- unsigned char buffer[64];
- int found_collision;
- int safe_hash;
- int detect_coll;
- int ubc_check;
- int reduced_round_coll;
- collision_block_callback callback;
-
- uint32_t ihv1[5];
- uint32_t ihv2[5];
- uint32_t m1[80];
- uint32_t m2[80];
- uint32_t states[80][5];
-} SHA1_CTX;
-
-/* Initialize SHA-1 context. */
-void SHA1DCInit(SHA1_CTX*);
-
-/*
- Function to enable safe SHA-1 hashing:
- Collision attacks are thwarted by hashing a detected near-collision block 3 times.
- Think of it as extending SHA-1 from 80-steps to 240-steps for such blocks:
- The best collision attacks against SHA-1 have complexity about 2^60,
- thus for 240-steps an immediate lower-bound for the best cryptanalytic attacks would be 2^180.
- An attacker would be better off using a generic birthday search of complexity 2^80.
-
- Enabling safe SHA-1 hashing will result in the correct SHA-1 hash for messages where no collision attack was detected,
- but it will result in a different SHA-1 hash for messages where a collision attack was detected.
- This will automatically invalidate SHA-1 based digital signature forgeries.
- Enabled by default.
-*/
-void SHA1DCSetSafeHash(SHA1_CTX*, int);
-
-/*
- Function to disable or enable the use of Unavoidable Bitconditions (provides a significant speed up).
- Enabled by default
- */
-void SHA1DCSetUseUBC(SHA1_CTX*, int);
-
-/*
- Function to disable or enable the use of Collision Detection.
- Enabled by default.
- */
-void SHA1DCSetUseDetectColl(SHA1_CTX*, int);
-
-/* function to disable or enable the detection of reduced-round SHA-1 collisions */
-/* disabled by default */
-void SHA1DCSetDetectReducedRoundCollision(SHA1_CTX*, int);
-
-/* function to set a callback function, pass NULL to disable */
-/* by default no callback set */
-void SHA1DCSetCallback(SHA1_CTX*, collision_block_callback);
-
-/* update SHA-1 context with buffer contents */
-void SHA1DCUpdate(SHA1_CTX*, const char*, size_t);
-
-/* obtain SHA-1 hash from SHA-1 context */
-/* returns: 0 = no collision detected, otherwise = collision found => warn user for active attack */
-int SHA1DCFinal(unsigned char[20], SHA1_CTX*);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H
-#include SHA1DC_CUSTOM_TRAILING_INCLUDE_SHA1_H
-#endif
-
-#endif
+++ /dev/null
-/***
-* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
-* Distributed under the MIT Software License.
-* See accompanying file LICENSE.txt or copy at
-* https://opensource.org/licenses/MIT
-***/
-
-/*
-// this file was generated by the 'parse_bitrel' program in the tools section
-// using the data files from directory 'tools/data/3565'
-//
-// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check
-// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper)
-// dm[80] is the expanded message block XOR-difference defined by the DV
-// testt is the step to do the recompression from for collision detection
-// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check
-//
-// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs
-// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met
-// thus one needs to do the recompression check for each DV that has its bit set
-//
-// ubc_check is programmatically generated and the unavoidable bitconditions have been hardcoded
-// a directly verifiable version named ubc_check_verify can be found in ubc_check_verify.c
-// ubc_check has been verified against ubc_check_verify using the 'ubc_check_test' program in the tools section
-*/
-
-#ifndef SHA1DC_NO_STANDARD_INCLUDES
-#include <stdint.h>
-#endif
-#ifdef SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C
-#include SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C
-#endif
-#include "ubc_check.h"
-
-static const uint32_t DV_I_43_0_bit = (uint32_t)(1) << 0;
-static const uint32_t DV_I_44_0_bit = (uint32_t)(1) << 1;
-static const uint32_t DV_I_45_0_bit = (uint32_t)(1) << 2;
-static const uint32_t DV_I_46_0_bit = (uint32_t)(1) << 3;
-static const uint32_t DV_I_46_2_bit = (uint32_t)(1) << 4;
-static const uint32_t DV_I_47_0_bit = (uint32_t)(1) << 5;
-static const uint32_t DV_I_47_2_bit = (uint32_t)(1) << 6;
-static const uint32_t DV_I_48_0_bit = (uint32_t)(1) << 7;
-static const uint32_t DV_I_48_2_bit = (uint32_t)(1) << 8;
-static const uint32_t DV_I_49_0_bit = (uint32_t)(1) << 9;
-static const uint32_t DV_I_49_2_bit = (uint32_t)(1) << 10;
-static const uint32_t DV_I_50_0_bit = (uint32_t)(1) << 11;
-static const uint32_t DV_I_50_2_bit = (uint32_t)(1) << 12;
-static const uint32_t DV_I_51_0_bit = (uint32_t)(1) << 13;
-static const uint32_t DV_I_51_2_bit = (uint32_t)(1) << 14;
-static const uint32_t DV_I_52_0_bit = (uint32_t)(1) << 15;
-static const uint32_t DV_II_45_0_bit = (uint32_t)(1) << 16;
-static const uint32_t DV_II_46_0_bit = (uint32_t)(1) << 17;
-static const uint32_t DV_II_46_2_bit = (uint32_t)(1) << 18;
-static const uint32_t DV_II_47_0_bit = (uint32_t)(1) << 19;
-static const uint32_t DV_II_48_0_bit = (uint32_t)(1) << 20;
-static const uint32_t DV_II_49_0_bit = (uint32_t)(1) << 21;
-static const uint32_t DV_II_49_2_bit = (uint32_t)(1) << 22;
-static const uint32_t DV_II_50_0_bit = (uint32_t)(1) << 23;
-static const uint32_t DV_II_50_2_bit = (uint32_t)(1) << 24;
-static const uint32_t DV_II_51_0_bit = (uint32_t)(1) << 25;
-static const uint32_t DV_II_51_2_bit = (uint32_t)(1) << 26;
-static const uint32_t DV_II_52_0_bit = (uint32_t)(1) << 27;
-static const uint32_t DV_II_53_0_bit = (uint32_t)(1) << 28;
-static const uint32_t DV_II_54_0_bit = (uint32_t)(1) << 29;
-static const uint32_t DV_II_55_0_bit = (uint32_t)(1) << 30;
-static const uint32_t DV_II_56_0_bit = (uint32_t)(1) << 31;
-
-dv_info_t sha1_dvs[] =
-{
- {1,43,0,58,0,0, { 0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161,0x80000599 } }
-, {1,44,0,58,0,1, { 0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803,0x80000161 } }
-, {1,45,0,58,0,2, { 0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c,0x00000803 } }
-, {1,46,0,58,0,3, { 0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6,0x8000004c } }
-, {1,46,2,58,0,4, { 0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a,0x00000132 } }
-, {1,47,0,58,0,5, { 0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408,0x800000e6 } }
-, {1,47,2,58,0,6, { 0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020,0x0000039a } }
-, {1,48,0,58,0,7, { 0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164,0x00000408 } }
-, {1,48,2,58,0,8, { 0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590,0x00001020 } }
-, {1,49,0,58,0,9, { 0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018,0x00000164 } }
-, {1,49,2,58,0,10, { 0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060,0x00000590 } }
-, {1,50,0,65,0,11, { 0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202,0x00000018 } }
-, {1,50,2,65,0,12, { 0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a,0x00000060 } }
-, {1,51,0,65,0,13, { 0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012,0x80000202 } }
-, {1,51,2,65,0,14, { 0xa0000003,0x20000030,0x60000000,0xe000002a,0x20000043,0xb0000040,0xd0000053,0xd0000022,0x20000000,0x60000032,0x60000043,0x20000040,0xe0000042,0x60000002,0x80000001,0x00000020,0x00000003,0x40000052,0x40000040,0xe0000052,0xa0000000,0x80000040,0x20000001,0x20000060,0x80000001,0x40000042,0xc0000043,0x40000022,0x00000003,0x40000042,0xc0000043,0xc0000022,0x00000001,0x40000002,0xc0000043,0x40000062,0x80000001,0x40000042,0x40000042,0x40000002,0x00000002,0x00000040,0x80000002,0x80000000,0x80000002,0x80000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000000,0x00000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000101,0x00000009,0x00000012,0x00000202,0x0000001a,0x00000124,0x0000040c,0x00000026,0x0000004a,0x0000080a } }
-, {1,52,0,65,0,15, { 0x04000010,0xe8000000,0x0800000c,0x18000000,0xb800000a,0xc8000010,0x2c000010,0xf4000014,0xb4000008,0x08000000,0x9800000c,0xd8000010,0x08000010,0xb8000010,0x98000000,0x60000000,0x00000008,0xc0000000,0x90000014,0x10000010,0xb8000014,0x28000000,0x20000010,0x48000000,0x08000018,0x60000000,0x90000010,0xf0000010,0x90000008,0xc0000000,0x90000010,0xf0000010,0xb0000008,0x40000000,0x90000000,0xf0000010,0x90000018,0x60000000,0x90000010,0x90000010,0x90000000,0x80000000,0x00000010,0xa0000000,0x20000000,0xa0000000,0x20000010,0x00000000,0x20000010,0x20000000,0x00000010,0x20000000,0x00000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000040,0x40000002,0x80000004,0x80000080,0x80000006,0x00000049,0x00000103,0x80000009,0x80000012 } }
-, {2,45,0,58,0,16, { 0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054,0x00000967 } }
-, {2,46,0,58,0,17, { 0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4,0x80000054 } }
-, {2,46,2,58,0,18, { 0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6,0x0000106a,0x00000b90,0x00000152 } }
-, {2,47,0,58,0,19, { 0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a,0x000002e4 } }
-, {2,48,0,58,0,20, { 0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d,0x8000041a } }
-, {2,49,0,58,0,21, { 0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b,0x8000016d } }
-, {2,49,2,58,0,22, { 0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c,0x000005b6 } }
-, {2,50,0,65,0,23, { 0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b,0x0000011b } }
-, {2,50,2,65,0,24, { 0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e,0x0000046c } }
-, {2,51,0,65,0,25, { 0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014,0x8000024b } }
-, {2,51,2,65,0,26, { 0x00000043,0xd0000072,0xf0000010,0xf000006a,0x80000040,0x90000070,0xb0000053,0x30000008,0x00000043,0xd0000072,0xb0000010,0xf0000062,0xc0000042,0x00000030,0xe0000042,0x20000060,0xe0000041,0x20000050,0xc0000041,0xe0000072,0xa0000003,0xc0000012,0x60000041,0xc0000032,0x20000001,0xc0000002,0xe0000042,0x60000042,0x80000002,0x00000000,0x00000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000000,0x00000040,0x80000001,0x00000060,0x80000003,0x40000002,0xc0000040,0xc0000002,0x80000000,0x80000000,0x80000002,0x00000040,0x00000002,0x80000000,0x80000000,0x80000000,0x00000002,0x00000040,0x00000000,0x80000040,0x80000002,0x00000000,0x80000000,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000080,0x00000004,0x00000009,0x00000105,0x00000089,0x00000016,0x0000020b,0x0000011b,0x0000012d,0x0000041e,0x00000224,0x00000050,0x0000092e } }
-, {2,52,0,65,0,27, { 0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089,0x00000014 } }
-, {2,53,0,65,0,28, { 0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107,0x00000089 } }
-, {2,54,0,65,0,29, { 0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b,0x80000107 } }
-, {2,55,0,65,0,30, { 0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046,0x4000004b } }
-, {2,56,0,65,0,31, { 0x2600001a,0x00000010,0x0400001c,0xcc000014,0x0c000002,0xc0000010,0xb400001c,0x3c000004,0xbc00001a,0x20000010,0x2400001c,0xec000014,0x0c000002,0xc0000010,0xb400001c,0x2c000004,0xbc000018,0xb0000010,0x0000000c,0xb8000010,0x08000018,0x78000010,0x08000014,0x70000010,0xb800001c,0xe8000000,0xb0000004,0x58000010,0xb000000c,0x48000000,0xb0000000,0xb8000010,0x98000010,0xa0000000,0x00000000,0x00000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0x20000000,0x00000010,0x60000000,0x00000018,0xe0000000,0x90000000,0x30000010,0xb0000000,0x20000000,0x20000000,0xa0000000,0x00000010,0x80000000,0x20000000,0x20000000,0x20000000,0x80000000,0x00000010,0x00000000,0x20000010,0xa0000000,0x00000000,0x20000000,0x20000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x00000020,0x00000001,0x40000002,0x40000041,0x40000022,0x80000005,0xc0000082,0xc0000046 } }
-, {0,0,0,0,0,0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
-};
-void ubc_check(const uint32_t W[80], uint32_t dvmask[1])
-{
- uint32_t mask = ~((uint32_t)(0));
- mask &= (((((W[44]^W[45])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_I_51_0_bit|DV_I_52_0_bit|DV_II_45_0_bit|DV_II_46_0_bit|DV_II_50_0_bit|DV_II_51_0_bit));
- mask &= (((((W[49]^W[50])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_II_45_0_bit|DV_II_50_0_bit|DV_II_51_0_bit|DV_II_55_0_bit|DV_II_56_0_bit));
- mask &= (((((W[48]^W[49])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_52_0_bit|DV_II_49_0_bit|DV_II_50_0_bit|DV_II_54_0_bit|DV_II_55_0_bit));
- mask &= ((((W[47]^(W[50]>>25))&(1<<4))-(1<<4)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_51_0_bit|DV_II_56_0_bit));
- mask &= (((((W[47]^W[48])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_51_0_bit|DV_II_48_0_bit|DV_II_49_0_bit|DV_II_53_0_bit|DV_II_54_0_bit));
- mask &= (((((W[46]>>4)^(W[49]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_50_0_bit|DV_II_55_0_bit));
- mask &= (((((W[46]^W[47])>>29)&1)-1) | ~(DV_I_43_0_bit|DV_I_50_0_bit|DV_II_47_0_bit|DV_II_48_0_bit|DV_II_52_0_bit|DV_II_53_0_bit));
- mask &= (((((W[45]>>4)^(W[48]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit|DV_II_49_0_bit|DV_II_54_0_bit));
- mask &= (((((W[45]^W[46])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_51_0_bit|DV_II_52_0_bit));
- mask &= (((((W[44]>>4)^(W[47]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_53_0_bit));
- mask &= (((((W[43]>>4)^(W[46]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_52_0_bit));
- mask &= (((((W[43]^W[44])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_I_50_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_49_0_bit|DV_II_50_0_bit));
- mask &= (((((W[42]>>4)^(W[45]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_51_0_bit));
- mask &= (((((W[41]>>4)^(W[44]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_50_0_bit));
- mask &= (((((W[40]^W[41])>>29)&1)-1) | ~(DV_I_44_0_bit|DV_I_47_0_bit|DV_I_48_0_bit|DV_II_46_0_bit|DV_II_47_0_bit|DV_II_56_0_bit));
- mask &= (((((W[54]^W[55])>>29)&1)-1) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_50_0_bit|DV_II_55_0_bit|DV_II_56_0_bit));
- mask &= (((((W[53]^W[54])>>29)&1)-1) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_49_0_bit|DV_II_54_0_bit|DV_II_55_0_bit));
- mask &= (((((W[52]^W[53])>>29)&1)-1) | ~(DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit|DV_II_53_0_bit|DV_II_54_0_bit));
- mask &= ((((W[50]^(W[53]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_48_0_bit|DV_II_54_0_bit));
- mask &= (((((W[50]^W[51])>>29)&1)-1) | ~(DV_I_47_0_bit|DV_II_46_0_bit|DV_II_51_0_bit|DV_II_52_0_bit|DV_II_56_0_bit));
- mask &= ((((W[49]^(W[52]>>25))&(1<<4))-(1<<4)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit|DV_II_47_0_bit|DV_II_53_0_bit));
- mask &= ((((W[48]^(W[51]>>25))&(1<<4))-(1<<4)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit|DV_II_46_0_bit|DV_II_52_0_bit));
- mask &= (((((W[42]^W[43])>>29)&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_I_50_0_bit|DV_II_48_0_bit|DV_II_49_0_bit));
- mask &= (((((W[41]^W[42])>>29)&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_I_49_0_bit|DV_II_47_0_bit|DV_II_48_0_bit));
- mask &= (((((W[40]>>4)^(W[43]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_50_0_bit|DV_II_49_0_bit|DV_II_56_0_bit));
- mask &= (((((W[39]>>4)^(W[42]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_49_0_bit|DV_II_48_0_bit|DV_II_55_0_bit));
- if (mask & (DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit))
- mask &= (((((W[38]>>4)^(W[41]>>29))&1)-1) | ~(DV_I_44_0_bit|DV_I_48_0_bit|DV_II_47_0_bit|DV_II_54_0_bit|DV_II_56_0_bit));
- mask &= (((((W[37]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_43_0_bit|DV_I_47_0_bit|DV_II_46_0_bit|DV_II_53_0_bit|DV_II_55_0_bit));
- if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit))
- mask &= (((((W[55]^W[56])>>29)&1)-1) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_51_0_bit|DV_II_56_0_bit));
- if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit))
- mask &= ((((W[52]^(W[55]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_50_0_bit|DV_II_56_0_bit));
- if (mask & (DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit))
- mask &= ((((W[51]^(W[54]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_47_0_bit|DV_II_49_0_bit|DV_II_55_0_bit));
- if (mask & (DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit))
- mask &= (((((W[51]^W[52])>>29)&1)-1) | ~(DV_I_48_0_bit|DV_II_47_0_bit|DV_II_52_0_bit|DV_II_53_0_bit));
- if (mask & (DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit))
- mask &= (((((W[36]>>4)^(W[40]>>29))&1)-1) | ~(DV_I_46_0_bit|DV_I_49_0_bit|DV_II_45_0_bit|DV_II_48_0_bit));
- if (mask & (DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit))
- mask &= ((0-(((W[53]^W[56])>>29)&1)) | ~(DV_I_52_0_bit|DV_II_48_0_bit|DV_II_49_0_bit));
- if (mask & (DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit))
- mask &= ((0-(((W[51]^W[54])>>29)&1)) | ~(DV_I_50_0_bit|DV_II_46_0_bit|DV_II_47_0_bit));
- if (mask & (DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit))
- mask &= ((0-(((W[50]^W[52])>>29)&1)) | ~(DV_I_49_0_bit|DV_I_51_0_bit|DV_II_45_0_bit));
- if (mask & (DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit))
- mask &= ((0-(((W[49]^W[51])>>29)&1)) | ~(DV_I_48_0_bit|DV_I_50_0_bit|DV_I_52_0_bit));
- if (mask & (DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit))
- mask &= ((0-(((W[48]^W[50])>>29)&1)) | ~(DV_I_47_0_bit|DV_I_49_0_bit|DV_I_51_0_bit));
- if (mask & (DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit))
- mask &= ((0-(((W[47]^W[49])>>29)&1)) | ~(DV_I_46_0_bit|DV_I_48_0_bit|DV_I_50_0_bit));
- if (mask & (DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit))
- mask &= ((0-(((W[46]^W[48])>>29)&1)) | ~(DV_I_45_0_bit|DV_I_47_0_bit|DV_I_49_0_bit));
- mask &= ((((W[45]^W[47])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit|DV_I_51_2_bit));
- if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit))
- mask &= ((0-(((W[45]^W[47])>>29)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_I_48_0_bit));
- mask &= (((((W[44]^W[46])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit|DV_I_50_2_bit));
- if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit))
- mask &= ((0-(((W[44]^W[46])>>29)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_I_47_0_bit));
- mask &= ((0-((W[41]^(W[42]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_II_46_2_bit|DV_II_51_2_bit));
- mask &= ((0-((W[40]^(W[41]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_51_2_bit|DV_II_50_2_bit));
- if (mask & (DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit))
- mask &= ((0-(((W[40]^W[42])>>4)&1)) | ~(DV_I_44_0_bit|DV_I_46_0_bit|DV_II_56_0_bit));
- mask &= ((0-((W[39]^(W[40]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_50_2_bit|DV_II_49_2_bit));
- if (mask & (DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit))
- mask &= ((0-(((W[39]^W[41])>>4)&1)) | ~(DV_I_43_0_bit|DV_I_45_0_bit|DV_II_55_0_bit));
- if (mask & (DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit))
- mask &= ((0-(((W[38]^W[40])>>4)&1)) | ~(DV_I_44_0_bit|DV_II_54_0_bit|DV_II_56_0_bit));
- if (mask & (DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit))
- mask &= ((0-(((W[37]^W[39])>>4)&1)) | ~(DV_I_43_0_bit|DV_II_53_0_bit|DV_II_55_0_bit));
- mask &= ((0-((W[36]^(W[37]>>5))&(1<<1))) | ~(DV_I_47_2_bit|DV_I_50_2_bit|DV_II_46_2_bit));
- if (mask & (DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit))
- mask &= (((((W[35]>>4)^(W[39]>>29))&1)-1) | ~(DV_I_45_0_bit|DV_I_48_0_bit|DV_II_47_0_bit));
- if (mask & (DV_I_48_0_bit|DV_II_48_0_bit))
- mask &= ((0-((W[63]^(W[64]>>5))&(1<<0))) | ~(DV_I_48_0_bit|DV_II_48_0_bit));
- if (mask & (DV_I_45_0_bit|DV_II_45_0_bit))
- mask &= ((0-((W[63]^(W[64]>>5))&(1<<1))) | ~(DV_I_45_0_bit|DV_II_45_0_bit));
- if (mask & (DV_I_47_0_bit|DV_II_47_0_bit))
- mask &= ((0-((W[62]^(W[63]>>5))&(1<<0))) | ~(DV_I_47_0_bit|DV_II_47_0_bit));
- if (mask & (DV_I_46_0_bit|DV_II_46_0_bit))
- mask &= ((0-((W[61]^(W[62]>>5))&(1<<0))) | ~(DV_I_46_0_bit|DV_II_46_0_bit));
- mask &= ((0-((W[61]^(W[62]>>5))&(1<<2))) | ~(DV_I_46_2_bit|DV_II_46_2_bit));
- if (mask & (DV_I_45_0_bit|DV_II_45_0_bit))
- mask &= ((0-((W[60]^(W[61]>>5))&(1<<0))) | ~(DV_I_45_0_bit|DV_II_45_0_bit));
- if (mask & (DV_II_51_0_bit|DV_II_54_0_bit))
- mask &= (((((W[58]^W[59])>>29)&1)-1) | ~(DV_II_51_0_bit|DV_II_54_0_bit));
- if (mask & (DV_II_50_0_bit|DV_II_53_0_bit))
- mask &= (((((W[57]^W[58])>>29)&1)-1) | ~(DV_II_50_0_bit|DV_II_53_0_bit));
- if (mask & (DV_II_52_0_bit|DV_II_54_0_bit))
- mask &= ((((W[56]^(W[59]>>25))&(1<<4))-(1<<4)) | ~(DV_II_52_0_bit|DV_II_54_0_bit));
- if (mask & (DV_II_51_0_bit|DV_II_52_0_bit))
- mask &= ((0-(((W[56]^W[59])>>29)&1)) | ~(DV_II_51_0_bit|DV_II_52_0_bit));
- if (mask & (DV_II_49_0_bit|DV_II_52_0_bit))
- mask &= (((((W[56]^W[57])>>29)&1)-1) | ~(DV_II_49_0_bit|DV_II_52_0_bit));
- if (mask & (DV_II_51_0_bit|DV_II_53_0_bit))
- mask &= ((((W[55]^(W[58]>>25))&(1<<4))-(1<<4)) | ~(DV_II_51_0_bit|DV_II_53_0_bit));
- if (mask & (DV_II_50_0_bit|DV_II_52_0_bit))
- mask &= ((((W[54]^(W[57]>>25))&(1<<4))-(1<<4)) | ~(DV_II_50_0_bit|DV_II_52_0_bit));
- if (mask & (DV_II_49_0_bit|DV_II_51_0_bit))
- mask &= ((((W[53]^(W[56]>>25))&(1<<4))-(1<<4)) | ~(DV_II_49_0_bit|DV_II_51_0_bit));
- mask &= ((((W[51]^(W[50]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_46_2_bit));
- mask &= ((((W[48]^W[50])&(1<<6))-(1<<6)) | ~(DV_I_50_2_bit|DV_II_46_2_bit));
- if (mask & (DV_I_51_0_bit|DV_I_52_0_bit))
- mask &= ((0-(((W[48]^W[55])>>29)&1)) | ~(DV_I_51_0_bit|DV_I_52_0_bit));
- mask &= ((((W[47]^W[49])&(1<<6))-(1<<6)) | ~(DV_I_49_2_bit|DV_I_51_2_bit));
- mask &= ((((W[48]^(W[47]>>5))&(1<<1))-(1<<1)) | ~(DV_I_47_2_bit|DV_II_51_2_bit));
- mask &= ((((W[46]^W[48])&(1<<6))-(1<<6)) | ~(DV_I_48_2_bit|DV_I_50_2_bit));
- mask &= ((((W[47]^(W[46]>>5))&(1<<1))-(1<<1)) | ~(DV_I_46_2_bit|DV_II_50_2_bit));
- mask &= ((0-((W[44]^(W[45]>>5))&(1<<1))) | ~(DV_I_51_2_bit|DV_II_49_2_bit));
- mask &= ((((W[43]^W[45])&(1<<6))-(1<<6)) | ~(DV_I_47_2_bit|DV_I_49_2_bit));
- mask &= (((((W[42]^W[44])>>6)&1)-1) | ~(DV_I_46_2_bit|DV_I_48_2_bit));
- mask &= ((((W[43]^(W[42]>>5))&(1<<1))-(1<<1)) | ~(DV_II_46_2_bit|DV_II_51_2_bit));
- mask &= ((((W[42]^(W[41]>>5))&(1<<1))-(1<<1)) | ~(DV_I_51_2_bit|DV_II_50_2_bit));
- mask &= ((((W[41]^(W[40]>>5))&(1<<1))-(1<<1)) | ~(DV_I_50_2_bit|DV_II_49_2_bit));
- if (mask & (DV_I_52_0_bit|DV_II_51_0_bit))
- mask &= ((((W[39]^(W[43]>>25))&(1<<4))-(1<<4)) | ~(DV_I_52_0_bit|DV_II_51_0_bit));
- if (mask & (DV_I_51_0_bit|DV_II_50_0_bit))
- mask &= ((((W[38]^(W[42]>>25))&(1<<4))-(1<<4)) | ~(DV_I_51_0_bit|DV_II_50_0_bit));
- if (mask & (DV_I_48_2_bit|DV_I_51_2_bit))
- mask &= ((0-((W[37]^(W[38]>>5))&(1<<1))) | ~(DV_I_48_2_bit|DV_I_51_2_bit));
- if (mask & (DV_I_50_0_bit|DV_II_49_0_bit))
- mask &= ((((W[37]^(W[41]>>25))&(1<<4))-(1<<4)) | ~(DV_I_50_0_bit|DV_II_49_0_bit));
- if (mask & (DV_II_52_0_bit|DV_II_54_0_bit))
- mask &= ((0-((W[36]^W[38])&(1<<4))) | ~(DV_II_52_0_bit|DV_II_54_0_bit));
- mask &= ((0-((W[35]^(W[36]>>5))&(1<<1))) | ~(DV_I_46_2_bit|DV_I_49_2_bit));
- if (mask & (DV_I_51_0_bit|DV_II_47_0_bit))
- mask &= ((((W[35]^(W[39]>>25))&(1<<3))-(1<<3)) | ~(DV_I_51_0_bit|DV_II_47_0_bit));
-if (mask) {
-
- if (mask & DV_I_43_0_bit)
- if (
- !((W[61]^(W[62]>>5)) & (1<<1))
- || !(!((W[59]^(W[63]>>25)) & (1<<5)))
- || !((W[58]^(W[63]>>30)) & (1<<0))
- ) mask &= ~DV_I_43_0_bit;
- if (mask & DV_I_44_0_bit)
- if (
- !((W[62]^(W[63]>>5)) & (1<<1))
- || !(!((W[60]^(W[64]>>25)) & (1<<5)))
- || !((W[59]^(W[64]>>30)) & (1<<0))
- ) mask &= ~DV_I_44_0_bit;
- if (mask & DV_I_46_2_bit)
- mask &= ((~((W[40]^W[42])>>2)) | ~DV_I_46_2_bit);
- if (mask & DV_I_47_2_bit)
- if (
- !((W[62]^(W[63]>>5)) & (1<<2))
- || !(!((W[41]^W[43]) & (1<<6)))
- ) mask &= ~DV_I_47_2_bit;
- if (mask & DV_I_48_2_bit)
- if (
- !((W[63]^(W[64]>>5)) & (1<<2))
- || !(!((W[48]^(W[49]<<5)) & (1<<6)))
- ) mask &= ~DV_I_48_2_bit;
- if (mask & DV_I_49_2_bit)
- if (
- !(!((W[49]^(W[50]<<5)) & (1<<6)))
- || !((W[42]^W[50]) & (1<<1))
- || !(!((W[39]^(W[40]<<5)) & (1<<6)))
- || !((W[38]^W[40]) & (1<<1))
- ) mask &= ~DV_I_49_2_bit;
- if (mask & DV_I_50_0_bit)
- mask &= ((((W[36]^W[37])<<7)) | ~DV_I_50_0_bit);
- if (mask & DV_I_50_2_bit)
- mask &= ((((W[43]^W[51])<<11)) | ~DV_I_50_2_bit);
- if (mask & DV_I_51_0_bit)
- mask &= ((((W[37]^W[38])<<9)) | ~DV_I_51_0_bit);
- if (mask & DV_I_51_2_bit)
- if (
- !(!((W[51]^(W[52]<<5)) & (1<<6)))
- || !(!((W[49]^W[51]) & (1<<6)))
- || !(!((W[37]^(W[37]>>5)) & (1<<1)))
- || !(!((W[35]^(W[39]>>25)) & (1<<5)))
- ) mask &= ~DV_I_51_2_bit;
- if (mask & DV_I_52_0_bit)
- mask &= ((((W[38]^W[39])<<11)) | ~DV_I_52_0_bit);
- if (mask & DV_II_46_2_bit)
- mask &= ((((W[47]^W[51])<<17)) | ~DV_II_46_2_bit);
- if (mask & DV_II_48_0_bit)
- if (
- !(!((W[36]^(W[40]>>25)) & (1<<3)))
- || !((W[35]^(W[40]<<2)) & (1<<30))
- ) mask &= ~DV_II_48_0_bit;
- if (mask & DV_II_49_0_bit)
- if (
- !(!((W[37]^(W[41]>>25)) & (1<<3)))
- || !((W[36]^(W[41]<<2)) & (1<<30))
- ) mask &= ~DV_II_49_0_bit;
- if (mask & DV_II_49_2_bit)
- if (
- !(!((W[53]^(W[54]<<5)) & (1<<6)))
- || !(!((W[51]^W[53]) & (1<<6)))
- || !((W[50]^W[54]) & (1<<1))
- || !(!((W[45]^(W[46]<<5)) & (1<<6)))
- || !(!((W[37]^(W[41]>>25)) & (1<<5)))
- || !((W[36]^(W[41]>>30)) & (1<<0))
- ) mask &= ~DV_II_49_2_bit;
- if (mask & DV_II_50_0_bit)
- if (
- !((W[55]^W[58]) & (1<<29))
- || !(!((W[38]^(W[42]>>25)) & (1<<3)))
- || !((W[37]^(W[42]<<2)) & (1<<30))
- ) mask &= ~DV_II_50_0_bit;
- if (mask & DV_II_50_2_bit)
- if (
- !(!((W[54]^(W[55]<<5)) & (1<<6)))
- || !(!((W[52]^W[54]) & (1<<6)))
- || !((W[51]^W[55]) & (1<<1))
- || !((W[45]^W[47]) & (1<<1))
- || !(!((W[38]^(W[42]>>25)) & (1<<5)))
- || !((W[37]^(W[42]>>30)) & (1<<0))
- ) mask &= ~DV_II_50_2_bit;
- if (mask & DV_II_51_0_bit)
- if (
- !(!((W[39]^(W[43]>>25)) & (1<<3)))
- || !((W[38]^(W[43]<<2)) & (1<<30))
- ) mask &= ~DV_II_51_0_bit;
- if (mask & DV_II_51_2_bit)
- if (
- !(!((W[55]^(W[56]<<5)) & (1<<6)))
- || !(!((W[53]^W[55]) & (1<<6)))
- || !((W[52]^W[56]) & (1<<1))
- || !((W[46]^W[48]) & (1<<1))
- || !(!((W[39]^(W[43]>>25)) & (1<<5)))
- || !((W[38]^(W[43]>>30)) & (1<<0))
- ) mask &= ~DV_II_51_2_bit;
- if (mask & DV_II_52_0_bit)
- if (
- !(!((W[59]^W[60]) & (1<<29)))
- || !(!((W[40]^(W[44]>>25)) & (1<<3)))
- || !(!((W[40]^(W[44]>>25)) & (1<<4)))
- || !((W[39]^(W[44]<<2)) & (1<<30))
- ) mask &= ~DV_II_52_0_bit;
- if (mask & DV_II_53_0_bit)
- if (
- !((W[58]^W[61]) & (1<<29))
- || !(!((W[57]^(W[61]>>25)) & (1<<4)))
- || !(!((W[41]^(W[45]>>25)) & (1<<3)))
- || !(!((W[41]^(W[45]>>25)) & (1<<4)))
- ) mask &= ~DV_II_53_0_bit;
- if (mask & DV_II_54_0_bit)
- if (
- !(!((W[58]^(W[62]>>25)) & (1<<4)))
- || !(!((W[42]^(W[46]>>25)) & (1<<3)))
- || !(!((W[42]^(W[46]>>25)) & (1<<4)))
- ) mask &= ~DV_II_54_0_bit;
- if (mask & DV_II_55_0_bit)
- if (
- !(!((W[59]^(W[63]>>25)) & (1<<4)))
- || !(!((W[57]^(W[59]>>25)) & (1<<4)))
- || !(!((W[43]^(W[47]>>25)) & (1<<3)))
- || !(!((W[43]^(W[47]>>25)) & (1<<4)))
- ) mask &= ~DV_II_55_0_bit;
- if (mask & DV_II_56_0_bit)
- if (
- !(!((W[60]^(W[64]>>25)) & (1<<4)))
- || !(!((W[44]^(W[48]>>25)) & (1<<3)))
- || !(!((W[44]^(W[48]>>25)) & (1<<4)))
- ) mask &= ~DV_II_56_0_bit;
-}
-
- dvmask[0]=mask;
-}
-
-#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C
-#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_C
-#endif
+++ /dev/null
-/***
-* Copyright 2017 Marc Stevens <marc@marc-stevens.nl>, Dan Shumow <danshu@microsoft.com>
-* Distributed under the MIT Software License.
-* See accompanying file LICENSE.txt or copy at
-* https://opensource.org/licenses/MIT
-***/
-
-/*
-// this file was generated by the 'parse_bitrel' program in the tools section
-// using the data files from directory 'tools/data/3565'
-//
-// sha1_dvs contains a list of SHA-1 Disturbance Vectors (DV) to check
-// dvType, dvK and dvB define the DV: I(K,B) or II(K,B) (see the paper)
-// dm[80] is the expanded message block XOR-difference defined by the DV
-// testt is the step to do the recompression from for collision detection
-// maski and maskb define the bit to check for each DV in the dvmask returned by ubc_check
-//
-// ubc_check takes as input an expanded message block and verifies the unavoidable bitconditions for all listed DVs
-// it returns a dvmask where each bit belonging to a DV is set if all unavoidable bitconditions for that DV have been met
-// thus one needs to do the recompression check for each DV that has its bit set
-*/
-
-#ifndef SHA1DC_UBC_CHECK_H
-#define SHA1DC_UBC_CHECK_H
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#ifndef SHA1DC_NO_STANDARD_INCLUDES
-#include <stdint.h>
-#endif
-
-#define DVMASKSIZE 1
-typedef struct { int dvType; int dvK; int dvB; int testt; int maski; int maskb; uint32_t dm[80]; } dv_info_t;
-extern dv_info_t sha1_dvs[];
-void ubc_check(const uint32_t W[80], uint32_t dvmask[DVMASKSIZE]);
-
-#define DOSTORESTATE58
-#define DOSTORESTATE65
-
-#define CHECK_DVMASK(_DVMASK) (0 != _DVMASK[0])
-
-#if defined(__cplusplus)
-}
-#endif
-
-#ifdef SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H
-#include SHA1DC_CUSTOM_TRAILING_INCLUDE_UBC_CHECK_H
-#endif
-
-#endif
#include "common.h"
#include "git2/sys/hashsig.h"
-#include "fileops.h"
+#include "futils.h"
#include "util.h"
typedef uint32_t hashsig_t;
__KHASH_IMPL(idx, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_equal)
__KHASH_IMPL(idxicase, static kh_inline, const git_index_entry *, git_index_entry *, 1, idxentry_hash, idxentry_icase_equal)
-int git_idxmap_alloc(git_idxmap **map)
+int git_idxmap_new(git_idxmap **out)
{
- if ((*map = kh_init(idx)) == NULL) {
- git_error_set_oom();
- return -1;
- }
+ *out = kh_init(idx);
+ GIT_ERROR_CHECK_ALLOC(*out);
return 0;
}
-int git_idxmap_icase_alloc(git_idxmap_icase **map)
+int git_idxmap_icase_new(git_idxmap_icase **out)
{
- if ((*map = kh_init(idxicase)) == NULL) {
- git_error_set_oom();
- return -1;
- }
+ *out = kh_init(idxicase);
+ GIT_ERROR_CHECK_ALLOC(*out);
return 0;
}
-void git_idxmap_insert(git_idxmap *map, const git_index_entry *key, void *value, int *rval)
+void git_idxmap_free(git_idxmap *map)
{
- khiter_t idx = kh_put(idx, map, key, rval);
-
- if ((*rval) >= 0) {
- if ((*rval) == 0)
- kh_key(map, idx) = key;
- kh_val(map, idx) = value;
- }
+ kh_destroy(idx, map);
}
-void git_idxmap_icase_insert(git_idxmap_icase *map, const git_index_entry *key, void *value, int *rval)
+void git_idxmap_icase_free(git_idxmap_icase *map)
{
- khiter_t idx = kh_put(idxicase, map, key, rval);
-
- if ((*rval) >= 0) {
- if ((*rval) == 0)
- kh_key(map, idx) = key;
- kh_val(map, idx) = value;
- }
+ kh_destroy(idxicase, map);
}
-size_t git_idxmap_lookup_index(git_idxmap *map, const git_index_entry *key)
+void git_idxmap_clear(git_idxmap *map)
{
- return kh_get(idx, map, key);
+ kh_clear(idx, map);
}
-size_t git_idxmap_icase_lookup_index(git_idxmap_icase *map, const git_index_entry *key)
+void git_idxmap_icase_clear(git_idxmap_icase *map)
{
- return kh_get(idxicase, map, key);
+ kh_clear(idxicase, map);
}
-void *git_idxmap_value_at(git_idxmap *map, size_t idx)
+int git_idxmap_resize(git_idxmap *map, size_t size)
{
- return kh_val(map, idx);
+ if (!git__is_uint32(size) ||
+ kh_resize(idx, map, (khiter_t)size) < 0) {
+ git_error_set_oom();
+ return -1;
+ }
+ return 0;
}
-int git_idxmap_valid_index(git_idxmap *map, size_t idx)
+int git_idxmap_icase_resize(git_idxmap_icase *map, size_t size)
{
- return idx != kh_end(map);
+ if (!git__is_uint32(size) ||
+ kh_resize(idxicase, map, (khiter_t)size) < 0) {
+ git_error_set_oom();
+ return -1;
+ }
+ return 0;
}
-int git_idxmap_has_data(git_idxmap *map, size_t idx)
+void *git_idxmap_get(git_idxmap *map, const git_index_entry *key)
{
- return kh_exist(map, idx);
+ size_t idx = kh_get(idx, map, key);
+ if (idx == kh_end(map) || !kh_exist(map, idx))
+ return NULL;
+ return kh_val(map, idx);
}
-void git_idxmap_resize(git_idxmap *map, size_t size)
+int git_idxmap_set(git_idxmap *map, const git_index_entry *key, void *value)
{
- kh_resize(idx, map, size);
-}
+ size_t idx;
+ int rval;
-void git_idxmap_icase_resize(git_idxmap_icase *map, size_t size)
-{
- kh_resize(idxicase, map, size);
-}
+ idx = kh_put(idx, map, key, &rval);
+ if (rval < 0)
+ return -1;
-void git_idxmap_free(git_idxmap *map)
-{
- kh_destroy(idx, map);
-}
+ if (rval == 0)
+ kh_key(map, idx) = key;
-void git_idxmap_icase_free(git_idxmap_icase *map)
-{
- kh_destroy(idxicase, map);
+ kh_val(map, idx) = value;
+
+ return 0;
}
-void git_idxmap_clear(git_idxmap *map)
+int git_idxmap_icase_set(git_idxmap_icase *map, const git_index_entry *key, void *value)
{
- kh_clear(idx, map);
+ size_t idx;
+ int rval;
+
+ idx = kh_put(idxicase, map, key, &rval);
+ if (rval < 0)
+ return -1;
+
+ if (rval == 0)
+ kh_key(map, idx) = key;
+
+ kh_val(map, idx) = value;
+
+ return 0;
}
-void git_idxmap_icase_clear(git_idxmap_icase *map)
+void *git_idxmap_icase_get(git_idxmap_icase *map, const git_index_entry *key)
{
- kh_clear(idxicase, map);
+ size_t idx = kh_get(idxicase, map, key);
+ if (idx == kh_end(map) || !kh_exist(map, idx))
+ return NULL;
+ return kh_val(map, idx);
}
-void git_idxmap_delete_at(git_idxmap *map, size_t idx)
+int git_idxmap_delete(git_idxmap *map, const git_index_entry *key)
{
+ khiter_t idx = kh_get(idx, map, key);
+ if (idx == kh_end(map))
+ return GIT_ENOTFOUND;
kh_del(idx, map, idx);
+ return 0;
}
-void git_idxmap_icase_delete_at(git_idxmap_icase *map, size_t idx)
+int git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key)
{
+ khiter_t idx = kh_get(idxicase, map, key);
+ if (idx == kh_end(map))
+ return GIT_ENOTFOUND;
kh_del(idxicase, map, idx);
-}
-
-void git_idxmap_delete(git_idxmap *map, const git_index_entry *key)
-{
- khiter_t idx = git_idxmap_lookup_index(map, key);
- if (git_idxmap_valid_index(map, idx))
- git_idxmap_delete_at(map, idx);
-}
-void git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key)
-{
- khiter_t idx = git_idxmap_icase_lookup_index(map, key);
- if (git_idxmap_valid_index((git_idxmap *)map, idx))
- git_idxmap_icase_delete_at(map, idx);
+ return 0;
}
#include "git2/index.h"
+/** A map with `git_index_entry`s as key. */
typedef struct kh_idx_s git_idxmap;
+/** A map with case-insensitive `git_index_entry`s as key */
typedef struct kh_idxicase_s git_idxmap_icase;
-int git_idxmap_alloc(git_idxmap **map);
-int git_idxmap_icase_alloc(git_idxmap_icase **map);
-void git_idxmap_insert(git_idxmap *map, const git_index_entry *key, void *value, int *rval);
-void git_idxmap_icase_insert(git_idxmap_icase *map, const git_index_entry *key, void *value, int *rval);
+/**
+ * Allocate a new index entry map.
+ *
+ * @param out Pointer to the map that shall be allocated.
+ * @return 0 on success, an error code if allocation has failed.
+ */
+int git_idxmap_new(git_idxmap **out);
-size_t git_idxmap_lookup_index(git_idxmap *map, const git_index_entry *key);
-size_t git_idxmap_icase_lookup_index(git_idxmap_icase *map, const git_index_entry *key);
-void *git_idxmap_value_at(git_idxmap *map, size_t idx);
-int git_idxmap_valid_index(git_idxmap *map, size_t idx);
-int git_idxmap_has_data(git_idxmap *map, size_t idx);
+/**
+ * Allocate a new case-insensitive index entry map.
+ *
+ * @param out Pointer to the map that shall be allocated.
+ * @return 0 on success, an error code if allocation has failed.
+ */
+int git_idxmap_icase_new(git_idxmap_icase **out);
-void git_idxmap_resize(git_idxmap *map, size_t size);
-void git_idxmap_icase_resize(git_idxmap_icase *map, size_t size);
+/**
+ * Free memory associated with the map.
+ *
+ * Note that this function will _not_ free values added to this
+ * map.
+ *
+ * @param map Pointer to the map that is to be free'd. May be
+ * `NULL`.
+ */
void git_idxmap_free(git_idxmap *map);
+
+/**
+ * Free memory associated with the map.
+ *
+ * Note that this function will _not_ free values added to this
+ * map.
+ *
+ * @param map Pointer to the map that is to be free'd. May be
+ * `NULL`.
+ */
void git_idxmap_icase_free(git_idxmap_icase *map);
+
+/**
+ * Clear all entries from the map.
+ *
+ * This function will remove all entries from the associated map.
+ * Memory associated with it will not be released, though.
+ *
+ * @param map Pointer to the map that shall be cleared. May be
+ * `NULL`.
+ */
void git_idxmap_clear(git_idxmap *map);
+
+/**
+ * Clear all entries from the map.
+ *
+ * This function will remove all entries from the associated map.
+ * Memory associated with it will not be released, though.
+ *
+ * @param map Pointer to the map that shall be cleared. May be
+ * `NULL`.
+ */
void git_idxmap_icase_clear(git_idxmap_icase *map);
-void git_idxmap_delete_at(git_idxmap *map, size_t idx);
-void git_idxmap_icase_delete_at(git_idxmap_icase *map, size_t idx);
+/**
+ * Resize the map by allocating more memory.
+ *
+ * @param map map that shall be resized
+ * @param size count of entries that the map shall hold
+ * @return `0` if the map was successfully resized, a negative
+ * error code otherwise
+ */
+int git_idxmap_resize(git_idxmap *map, size_t size);
-void git_idxmap_delete(git_idxmap *map, const git_index_entry *key);
-void git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key);
+/**
+ * Resize the map by allocating more memory.
+ *
+ * @param map map that shall be resized
+ * @param size count of entries that the map shall hold
+ * @return `0` if the map was successfully resized, a negative
+ * error code otherwise
+ */
+int git_idxmap_icase_resize(git_idxmap_icase *map, size_t size);
+
+/**
+ * Return value associated with the given key.
+ *
+ * @param map map to search key in
+ * @param key key to search for; the index entry will be searched
+ * for by its case-sensitive path
+ * @return value associated with the given key or NULL if the key was not found
+ */
+void *git_idxmap_get(git_idxmap *map, const git_index_entry *key);
+
+/**
+ * Return value associated with the given key.
+ *
+ * @param map map to search key in
+ * @param key key to search for; the index entry will be searched
+ * for by its case-insensitive path
+ * @return value associated with the given key or NULL if the key was not found
+ */
+void *git_idxmap_icase_get(git_idxmap_icase *map, const git_index_entry *key);
+
+/**
+ * Set the entry for key to value.
+ *
+ * If the map has no corresponding entry for the given key, a new
+ * entry will be created with the given value. If an entry exists
+ * already, its value will be updated to match the given value.
+ *
+ * @param map map to create new entry in
+ * @param key key to set
+ * @param value value to associate the key with; may be NULL
+ * @return zero if the key was successfully set, a negative error
+ * code otherwise
+ */
+int git_idxmap_set(git_idxmap *map, const git_index_entry *key, void *value);
+
+/**
+ * Set the entry for key to value.
+ *
+ * If the map has no corresponding entry for the given key, a new
+ * entry will be created with the given value. If an entry exists
+ * already, its value will be updated to match the given value.
+ *
+ * @param map map to create new entry in
+ * @param key key to set
+ * @param value value to associate the key with; may be NULL
+ * @return zero if the key was successfully set, a negative error
+ * code otherwise
+ */
+int git_idxmap_icase_set(git_idxmap_icase *map, const git_index_entry *key, void *value);
+
+/**
+ * Delete an entry from the map.
+ *
+ * Delete the given key and its value from the map. If no such
+ * key exists, this will do nothing.
+ *
+ * @param map map to delete key in
+ * @param key key to delete
+ * @return `0` if the key has been deleted, GIT_ENOTFOUND if no
+ * such key was found, a negative code in case of an
+ * error
+ */
+int git_idxmap_delete(git_idxmap *map, const git_index_entry *key);
+
+/**
+ * Delete an entry from the map.
+ *
+ * Delete the given key and its value from the map. If no such
+ * key exists, this will do nothing.
+ *
+ * @param map map to delete key in
+ * @param key key to delete
+ * @return `0` if the key has been deleted, GIT_ENOTFOUND if no
+ * such key was found, a negative code in case of an
+ * error
+ */
+int git_idxmap_icase_delete(git_idxmap_icase *map, const git_index_entry *key);
#endif
#include "attrcache.h"
#include "path.h"
#include "config.h"
-#include "fnmatch.h"
+#include "wildmatch.h"
#define GIT_IGNORE_INTERNAL "[internal]exclude"
*/
static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match)
{
- int error = 0, fnflags;
+ int error = 0, wildmatch_flags;
size_t i;
git_attr_fnmatch *rule;
char *path;
*out = 0;
- fnflags = FNM_PATHNAME;
+ wildmatch_flags = WM_PATHNAME;
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
- fnflags |= FNM_IGNORECASE;
+ wildmatch_flags |= WM_CASEFOLD;
/* path of the file relative to the workdir, so we match the rules in subdirs */
if (match->containing_dir) {
if (git_buf_oom(&buf))
goto out;
- if ((error = p_fnmatch(git_buf_cstr(&buf), path, fnflags)) < 0) {
- git_error_set(GIT_ERROR_INVALID, "error matching pattern");
- goto out;
- }
-
/* if we found a match, we want to keep this rule */
- if (error != FNM_NOMATCH) {
+ if ((wildmatch(git_buf_cstr(&buf), path, wildmatch_flags)) == WM_MATCH) {
*out = 1;
error = 0;
goto out;
}
static int parse_ignore_file(
- git_repository *repo, git_attr_file *attrs, const char *data)
+ git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros)
{
int error = 0;
int ignore_case = false;
const char *scan = data, *context = NULL;
git_attr_fnmatch *match = NULL;
- if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
+ GIT_UNUSED(allow_macros);
+
+ if (git_repository__configmap_lookup(&ignore_case, repo, GIT_CONFIGMAP_IGNORECASE) < 0)
git_error_clear();
/* if subdir file path, convert context for file paths */
}
match->flags =
- GIT_ATTR_FNMATCH_ALLOWSPACE |
- GIT_ATTR_FNMATCH_ALLOWNEG |
- GIT_ATTR_FNMATCH_NOLEADINGDIR;
+ GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG;
if (!(error = git_attr_fnmatch__parse(
match, &attrs->pool, context, &scan)))
int error = 0;
git_attr_file *file = NULL;
- error = git_attr_cache__get(
- &file, ignores->repo, NULL, GIT_ATTR_FILE__FROM_FILE,
- base, filename, parse_ignore_file);
+ error = git_attr_cache__get(&file, ignores->repo, NULL, GIT_ATTR_FILE__FROM_FILE,
+ base, filename, parse_ignore_file, false);
if (error < 0)
return error;
if ((error = git_attr_cache__init(repo)) < 0)
return error;
- error = git_attr_cache__get(
- out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL, GIT_IGNORE_INTERNAL, NULL);
+ error = git_attr_cache__get(out, repo, NULL, GIT_ATTR_FILE__IN_MEMORY, NULL,
+ GIT_IGNORE_INTERNAL, NULL, false);
/* if internal rules list is empty, insert default rules */
if (!error && !(*out)->rules.length)
- error = parse_ignore_file(repo, *out, GIT_IGNORE_DEFAULT_RULES);
+ error = parse_ignore_file(repo, *out, GIT_IGNORE_DEFAULT_RULES, false);
return error;
}
ignores->repo = repo;
/* Read the ignore_case flag */
- if ((error = git_repository__cvar(
- &ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0)
+ if ((error = git_repository__configmap_lookup(
+ &ignores->ignore_case, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
goto cleanup;
if ((error = git_attr_cache__init(repo)) < 0)
goto cleanup;
}
- if ((error = git_repository_item_path(&infopath,
- repo, GIT_REPOSITORY_ITEM_INFO)) < 0)
- goto cleanup;
-
- /* load .git/info/exclude */
- error = push_ignore_file(
- ignores, &ignores->ign_global,
- infopath.ptr, GIT_IGNORE_FILE_INREPO);
- if (error < 0)
- goto cleanup;
+ /* load .git/info/exclude if possible */
+ if ((error = git_repository_item_path(&infopath, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
+ (error = push_ignore_file(ignores, &ignores->ign_global, infopath.ptr, GIT_IGNORE_FILE_INREPO)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto cleanup;
+ error = 0;
+ }
/* load core.excludesfile */
if (git_repository_attr_cache(repo)->cfg_excl_file != NULL)
int git_ignore__lookup(
int *out, git_ignores *ignores, const char *pathname, git_dir_flag dir_flag)
{
- unsigned int i;
+ size_t i;
git_attr_file *file;
git_attr_path path;
if (ignore_lookup_in_rules(out, ignores->ign_internal, &path))
goto cleanup;
- /* next process files in the path */
- git_vector_foreach(&ignores->ign_path, i, file) {
+ /* next process files in the path.
+ * this process has to process ignores in reverse order
+ * to ensure correct prioritization of rules
+ */
+ git_vector_rforeach(&ignores->ign_path, i, file) {
if (ignore_lookup_in_rules(out, file, &path))
goto cleanup;
}
if ((error = get_internal_ignores(&ign_internal, repo)) < 0)
return error;
- error = parse_ignore_file(repo, ign_internal, rules);
+ error = parse_ignore_file(repo, ign_internal, rules, false);
git_attr_file__free(ign_internal);
return error;
if (!(error = git_attr_file__clear_rules(ign_internal, true)))
error = parse_ignore_file(
- repo, ign_internal, GIT_IGNORE_DEFAULT_RULES);
+ repo, ign_internal, GIT_IGNORE_DEFAULT_RULES, false);
git_attr_file__free(ign_internal);
return error;
#include "git2/config.h"
#include "git2/sys/index.h"
-#define INSERT_IN_MAP_EX(idx, map, e, err) do { \
- if ((idx)->ignore_case) \
- git_idxmap_icase_insert((git_idxmap_icase *) (map), (e), (e), (err)); \
- else \
- git_idxmap_insert((map), (e), (e), (err)); \
- } while (0)
-
-#define INSERT_IN_MAP(idx, e, err) INSERT_IN_MAP_EX(idx, (idx)->entries_map, e, err)
-
-#define LOOKUP_IN_MAP(p, idx, k) do { \
- if ((idx)->ignore_case) \
- (p) = git_idxmap_icase_lookup_index((git_idxmap_icase *) index->entries_map, (k)); \
- else \
- (p) = git_idxmap_lookup_index(index->entries_map, (k)); \
- } while (0)
-
-#define DELETE_IN_MAP(idx, e) do { \
- if ((idx)->ignore_case) \
- git_idxmap_icase_delete((git_idxmap_icase *) (idx)->entries_map, (e)); \
- else \
- git_idxmap_delete((idx)->entries_map, (e)); \
- } while (0)
-
static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
unsigned int flags,
git_index_matched_path_cb cb, void *payload);
static void index_entry_free(git_index_entry *entry);
static void index_entry_reuc_free(git_index_reuc_entry *reuc);
+GIT_INLINE(int) index_map_set(git_idxmap *map, git_index_entry *e, bool ignore_case)
+{
+ if (ignore_case)
+ return git_idxmap_icase_set((git_idxmap_icase *) map, e, e);
+ else
+ return git_idxmap_set(map, e, e);
+}
+
+GIT_INLINE(int) index_map_delete(git_idxmap *map, git_index_entry *e, bool ignore_case)
+{
+ if (ignore_case)
+ return git_idxmap_icase_delete((git_idxmap_icase *) map, e);
+ else
+ return git_idxmap_delete(map, e);
+}
+
+GIT_INLINE(int) index_map_resize(git_idxmap *map, size_t count, bool ignore_case)
+{
+ if (ignore_case)
+ return git_idxmap_icase_resize((git_idxmap_icase *) map, count);
+ else
+ return git_idxmap_resize(map, count);
+}
+
int git_index_entry_srch(const void *key, const void *array_member)
{
const struct entry_srch_key *srch_key = key;
index = git__calloc(1, sizeof(git_index));
GIT_ERROR_CHECK_ALLOC(index);
- git_pool_init(&index->tree_pool, 1);
+ if (git_pool_init(&index->tree_pool, 1) < 0)
+ goto fail;
if (index_path != NULL) {
index->index_file_path = git__strdup(index_path);
}
if (git_vector_init(&index->entries, 32, git_index_entry_cmp) < 0 ||
- git_idxmap_alloc(&index->entries_map) < 0 ||
- git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
- git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
- git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
+ git_idxmap_new(&index->entries_map) < 0 ||
+ git_vector_init(&index->names, 8, conflict_name_cmp) < 0 ||
+ git_vector_init(&index->reuc, 8, reuc_cmp) < 0 ||
+ git_vector_init(&index->deleted, 8, git_index_entry_cmp) < 0)
goto fail;
index->entries_cmp_path = git__strcmp_cb;
if (entry != NULL) {
git_tree_cache_invalidate_path(index->tree, entry->path);
- DELETE_IN_MAP(index, entry);
+ index_map_delete(index->entries_map, entry, index->ignore_case);
}
error = git_vector_remove(&index->entries, pos);
git_idxmap_clear(index->entries_map);
while (!error && index->entries.length > 0)
error = index_remove_entry(index, index->entries.length - 1);
+
+ if (error)
+ goto done;
+
index_free_deleted(index);
- git_index_reuc_clear(index);
- git_index_name_clear(index);
+ if ((error = git_index_name_clear(index)) < 0 ||
+ (error = git_index_reuc_clear(index)) < 0)
+ goto done;
git_futils_filestamp_set(&index->stamp, NULL);
+done:
return error;
}
return create_index_error(
-1, "cannot access repository to set index caps");
- if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
+ if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_IGNORECASE))
index->ignore_case = (val != 0);
- if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE))
+ if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FILEMODE))
index->distrust_filemode = (val == 0);
- if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS))
+ if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_SYMLINKS))
index->no_symlinks = (val == 0);
}
else {
git_index *index, const char *path, int stage)
{
git_index_entry key = {{ 0 }};
- size_t pos;
+ git_index_entry *value;
assert(index);
key.path = path;
GIT_INDEX_ENTRY_STAGE_SET(&key, stage);
- LOOKUP_IN_MAP(pos, index, &key);
+ if (index->ignore_case)
+ value = git_idxmap_icase_get((git_idxmap_icase *) index->entries_map, &key);
+ else
+ value = git_idxmap_get(index->entries_map, &key);
- if (git_idxmap_valid_index(index->entries_map, pos))
- return git_idxmap_value_at(index->entries_map, pos);
+ if (!value) {
+ git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path);
+ return NULL;
+ }
- git_error_set(GIT_ERROR_INDEX, "index does not contain '%s'", path);
- return NULL;
+ return value;
}
void git_index_entry__init_from_stat(
* at the sorted position. (Since we re-sort after each insert to
* check for dups, this is actually cheaper in the long run.)
*/
- if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0)
+ if ((error = git_vector_insert_sorted(&index->entries, entry, index_no_dups)) < 0 ||
+ (error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0)
goto out;
-
- INSERT_IN_MAP(index, entry, &error);
}
index->dirty = 1;
return (is_file_or_link(filemode) || filemode == GIT_FILEMODE_COMMIT);
}
-int git_index_add_frombuffer(
+int git_index_add_from_buffer(
git_index *index, const git_index_entry *source_entry,
const void *buffer, size_t len)
{
return -1;
}
+ if (len > UINT32_MAX) {
+ git_error_set(GIT_ERROR_INDEX, "buffer is too large");
+ return -1;
+ }
+
if (index_entry_dup(&entry, index, source_entry) < 0)
return -1;
- error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
+ error = git_blob_create_from_buffer(&id, INDEX_OWNER(index), buffer, len);
if (error < 0) {
index_entry_free(entry);
return error;
}
git_oid_cpy(&entry->id, &id);
- entry->file_size = len;
+ entry->file_size = (uint32_t)len;
if ((error = index_insert(index, &entry, 1, true, true, true)) < 0)
return error;
int git_index__fill(git_index *index, const git_vector *source_entries)
{
const git_index_entry *source_entry = NULL;
+ int error = 0;
size_t i;
- int ret = 0;
assert(index);
if (!source_entries->length)
return 0;
- git_vector_size_hint(&index->entries, source_entries->length);
- git_idxmap_resize(index->entries_map, (size_t)(source_entries->length * 1.3));
+ if (git_vector_size_hint(&index->entries, source_entries->length) < 0 ||
+ index_map_resize(index->entries_map, (size_t)(source_entries->length * 1.3),
+ index->ignore_case) < 0)
+ return -1;
git_vector_foreach(source_entries, i, source_entry) {
git_index_entry *entry = NULL;
- if ((ret = index_entry_dup(&entry, index, source_entry)) < 0)
+ if ((error = index_entry_dup(&entry, index, source_entry)) < 0)
break;
index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen);
entry->flags_extended |= GIT_INDEX_ENTRY_UPTODATE;
entry->mode = git_index__create_mode(entry->mode);
- if ((ret = git_vector_insert(&index->entries, entry)) < 0)
+ if ((error = git_vector_insert(&index->entries, entry)) < 0)
break;
- INSERT_IN_MAP(index, entry, &ret);
- if (ret < 0)
+ if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0)
break;
index->dirty = 1;
}
- if (!ret)
+ if (!error)
git_vector_sort(&index->entries);
- return ret;
+ return error;
}
remove_key.path = path;
GIT_INDEX_ENTRY_STAGE_SET(&remove_key, stage);
- DELETE_IN_MAP(index, &remove_key);
+ index_map_delete(index->entries_map, &remove_key, index->ignore_case);
if (index_find(&position, index, path, 0, stage) < 0) {
git_error_set(
return 0;
}
-void git_index_name_clear(git_index *index)
+int git_index_name_clear(git_index *index)
{
size_t i;
git_index_name_entry *conflict_name;
git_vector_clear(&index->names);
index->dirty = 1;
+
+ return 0;
}
size_t git_index_reuc_entrycount(git_index *index)
return error;
}
-void git_index_reuc_clear(git_index *index)
+int git_index_reuc_clear(git_index *index)
{
size_t i;
git_vector_clear(&index->reuc);
index->dirty = 1;
+
+ return 0;
}
static int index_error_invalid(const char *message)
assert(!index->entries.length);
- if (index->ignore_case)
- git_idxmap_icase_resize((git_idxmap_icase *) index->entries_map, header.entry_count);
- else
- git_idxmap_resize(index->entries_map, header.entry_count);
+ if ((error = index_map_resize(index->entries_map, header.entry_count, index->ignore_case)) < 0)
+ return error;
/* Parse all the entries */
for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) {
goto done;
}
- INSERT_IN_MAP(index, entry, &error);
-
- if (error < 0) {
+ if ((error = index_map_set(index->entries_map, entry, index->ignore_case)) < 0) {
index_entry_free(entry);
goto done;
}
++same_len;
}
path_len -= same_len;
- varint_len = git_encode_varint(NULL, 0, same_len);
+ varint_len = git_encode_varint(NULL, 0, strlen(last) - same_len);
}
disk_size = index_entry_size(path_len, varint_len, entry->flags);
ondisk.flags = htons(entry->flags);
if (entry->flags & GIT_INDEX_ENTRY_EXTENDED) {
+ const size_t path_offset = offsetof(struct entry_long, path);
struct entry_long ondisk_ext;
memcpy(&ondisk_ext, &ondisk, sizeof(struct entry_short));
ondisk_ext.flags_extended = htons(entry->flags_extended &
GIT_INDEX_ENTRY_EXTENDED_FLAGS);
- memcpy(mem, &ondisk_ext, offsetof(struct entry_long, path));
- path = ((struct entry_long*)mem)->path;
- disk_size -= offsetof(struct entry_long, path);
+ memcpy(mem, &ondisk_ext, path_offset);
+ path = (char *)mem + path_offset;
+ disk_size -= path_offset;
} else {
- memcpy(mem, &ondisk, offsetof(struct entry_short, path));
- path = ((struct entry_short*)mem)->path;
- disk_size -= offsetof(struct entry_short, path);
+ const size_t path_offset = offsetof(struct entry_short, path);
+ memcpy(mem, &ondisk, path_offset);
+ path = (char *)mem + path_offset;
+ disk_size -= path_offset;
}
if (last) {
varint_len = git_encode_varint((unsigned char *) path,
- disk_size, same_len);
+ disk_size, strlen(last) - same_len);
assert(varint_len > 0);
path += varint_len;
disk_size -= varint_len;
size_t i;
git_index_entry *e;
- if (git_idxmap_alloc(&entries_map) < 0)
+ if (git_idxmap_new(&entries_map) < 0)
return -1;
git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */
if ((error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data)) < 0)
goto cleanup;
- if (index->ignore_case)
- git_idxmap_icase_resize((git_idxmap_icase *) entries_map, entries.length);
- else
- git_idxmap_resize(entries_map, entries.length);
+ if ((error = index_map_resize(entries_map, entries.length, index->ignore_case)) < 0)
+ goto cleanup;
git_vector_foreach(&entries, i, e) {
- INSERT_IN_MAP_EX(index, entries_map, e, &error);
-
- if (error < 0) {
+ if ((error = index_map_set(entries_map, e, index->ignore_case)) < 0) {
git_error_set(GIT_ERROR_INDEX, "failed to insert entry into map");
return error;
}
assert((new_iterator->flags & GIT_ITERATOR_DONT_IGNORE_CASE));
if ((error = git_vector_init(&new_entries, new_length_hint, index->entries._cmp)) < 0 ||
- (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
- (error = git_idxmap_alloc(&new_entries_map)) < 0)
+ (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 ||
+ (error = git_idxmap_new(&new_entries_map)) < 0)
goto done;
- if (index->ignore_case && new_length_hint)
- git_idxmap_icase_resize((git_idxmap_icase *) new_entries_map, new_length_hint);
- else if (new_length_hint)
- git_idxmap_resize(new_entries_map, new_length_hint);
+ if (new_length_hint && (error = index_map_resize(new_entries_map, new_length_hint,
+ index->ignore_case)) < 0)
+ goto done;
opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE |
GIT_ITERATOR_INCLUDE_CONFLICTS;
if (add_entry) {
if ((error = git_vector_insert(&new_entries, add_entry)) == 0)
- INSERT_IN_MAP_EX(index, new_entries_map, add_entry, &error);
+ error = index_map_set(new_entries_map, add_entry,
+ index->ignore_case);
}
if (remove_entry && error >= 0)
}
}
- git_index_name_clear(index);
- git_index_reuc_clear(index);
+ if ((error = git_index_name_clear(index)) < 0 ||
+ (error = git_index_reuc_clear(index)) < 0)
+ goto done;
git_vector_swap(&new_entries, &index->entries);
new_entries_map = git__swap(index->entries_map, new_entries_map);
git_index_free(writer->index);
writer->index = NULL;
}
+
+/* Deprecated functions */
+
+#ifndef GIT_DEPRECATE_HARD
+int git_index_add_frombuffer(
+ git_index *index, const git_index_entry *source_entry,
+ const void *buffer, size_t len)
+{
+ return git_index_add_from_buffer(index, source_entry, buffer, len);
+}
+#endif
#include "common.h"
-#include "fileops.h"
+#include "futils.h"
#include "filebuf.h"
#include "vector.h"
#include "idxmap.h"
#include "pack.h"
#include "filebuf.h"
#include "oid.h"
+#include "oidarray.h"
#include "oidmap.h"
#include "zstream.h"
#include "object.h"
struct git_pack_header hdr;
struct git_pack_file *pack;
unsigned int mode;
- git_off_t off;
- git_off_t entry_start;
+ off64_t off;
+ off64_t entry_start;
git_object_t entry_type;
git_buf entry_data;
git_packfile_stream stream;
unsigned int fanout[256];
git_hash_ctx hash_ctx;
git_oid hash;
- git_transfer_progress_cb progress_cb;
+ git_indexer_progress_cb progress_cb;
void *progress_payload;
char objbuf[8*1024];
};
struct delta_info {
- git_off_t delta_off;
+ off64_t delta_off;
};
const git_oid *git_indexer_hash(const git_indexer *idx)
return git_oid__cmp(&entrya->oid, &entryb->oid);
}
-int git_indexer_init_options(git_indexer_options *opts, unsigned int version)
+int git_indexer_options_init(git_indexer_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_indexer_options, GIT_INDEXER_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_indexer_init_options(git_indexer_options *opts, unsigned int version)
+{
+ return git_indexer_options_init(opts, version);
+}
+#endif
+
int git_indexer_new(
git_indexer **out,
const char *prefix,
idx->progress_cb = opts.progress_cb;
idx->progress_payload = opts.progress_cb_payload;
idx->mode = mode ? mode : GIT_PACK_FILE_MODE;
- git_hash_ctx_init(&idx->hash_ctx);
- git_hash_ctx_init(&idx->trailer);
git_buf_init(&idx->entry_data, 0);
- idx->expected_oids = git_oidmap_alloc();
- GIT_ERROR_CHECK_ALLOC(idx->expected_oids);
+
+ if ((error = git_hash_ctx_init(&idx->hash_ctx)) < 0 ||
+ (error = git_hash_ctx_init(&idx->trailer)) < 0 ||
+ (error = git_oidmap_new(&idx->expected_oids)) < 0)
+ goto cleanup;
idx->do_verify = opts.verify;
return 0;
}
-static int hash_header(git_hash_ctx *ctx, git_off_t len, git_object_t type)
+static int hash_header(git_hash_ctx *ctx, off64_t len, git_object_t type)
{
char buffer[64];
size_t hdrlen;
if (type == GIT_OBJECT_REF_DELTA) {
idx->off += GIT_OID_RAWSZ;
} else {
- git_off_t base_off = get_delta_base(idx->pack, &w, &idx->off, type, idx->entry_start);
+ off64_t base_off;
+ int error = get_delta_base(&base_off, idx->pack, &w, &idx->off, type, idx->entry_start);
git_mwindow_close(&w);
- if (base_off < 0)
- return (int)base_off;
+ if (error < 0)
+ return error;
}
return 0;
return 0;
}
-static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, git_off_t start, git_off_t size)
+static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, off64_t start, off64_t size)
{
void *ptr;
uint32_t crc;
return 0;
}
-static void add_expected_oid(git_indexer *idx, const git_oid *oid)
+static int add_expected_oid(git_indexer *idx, const git_oid *oid)
{
- int ret;
-
/*
* If we know about that object because it is stored in our ODB or
* because we have already processed it as part of our pack file, we do
!git_oidmap_exists(idx->pack->idx_cache, oid) &&
!git_oidmap_exists(idx->expected_oids, oid)) {
git_oid *dup = git__malloc(sizeof(*oid));
+ GIT_ERROR_CHECK_ALLOC(dup);
git_oid_cpy(dup, oid);
- git_oidmap_put(idx->expected_oids, dup, &ret);
+ return git_oidmap_set(idx->expected_oids, dup, dup);
}
+
+ return 0;
}
static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj)
{
git_object *object;
- size_t keyidx;
+ git_oid *expected;
int error;
if (obj->type != GIT_OBJECT_BLOB &&
if ((error = git_object__from_raw(&object, obj->data, obj->len, obj->type)) < 0)
goto out;
- keyidx = git_oidmap_lookup_index(idx->expected_oids, &object->cached.oid);
- if (git_oidmap_valid_index(idx->expected_oids, keyidx)) {
- const git_oid *key = git_oidmap_key(idx->expected_oids, keyidx);
- git__free((git_oid *) key);
- git_oidmap_delete_at(idx->expected_oids, keyidx);
+ if ((expected = git_oidmap_get(idx->expected_oids, &object->cached.oid)) != NULL) {
+ git_oidmap_delete(idx->expected_oids, &object->cached.oid);
+ git__free(expected);
}
/*
size_t i;
git_array_foreach(tree->entries, i, entry)
- add_expected_oid(idx, entry->oid);
+ if (add_expected_oid(idx, entry->oid) < 0)
+ goto out;
break;
}
size_t i;
git_array_foreach(commit->parent_ids, i, parent_oid)
- add_expected_oid(idx, parent_oid);
+ if (add_expected_oid(idx, parent_oid) < 0)
+ goto out;
- add_expected_oid(idx, &commit->tree_id);
+ if (add_expected_oid(idx, &commit->tree_id) < 0)
+ goto out;
break;
}
{
git_tag *tag = (git_tag *) object;
- add_expected_oid(idx, &tag->target);
+ if (add_expected_oid(idx, &tag->target) < 0)
+ goto out;
break;
}
static int store_object(git_indexer *idx)
{
int i, error;
- size_t k;
git_oid oid;
struct entry *entry;
- git_off_t entry_size;
+ off64_t entry_size;
struct git_pack_entry *pentry;
- git_off_t entry_start = idx->entry_start;
+ off64_t entry_start = idx->entry_start;
entry = git__calloc(1, sizeof(*entry));
GIT_ERROR_CHECK_ALLOC(entry);
pentry = git__calloc(1, sizeof(struct git_pack_entry));
GIT_ERROR_CHECK_ALLOC(pentry);
- git_hash_final(&oid, &idx->hash_ctx);
+ if (git_hash_final(&oid, &idx->hash_ctx)) {
+ git__free(pentry);
+ goto on_error;
+ }
entry_size = idx->off - entry_start;
if (entry_start > UINT31_MAX) {
entry->offset = UINT32_MAX;
git_oid_cpy(&pentry->sha1, &oid);
pentry->offset = entry_start;
- k = git_oidmap_put(idx->pack->idx_cache, &pentry->sha1, &error);
- if (error == -1) {
+ if (git_oidmap_exists(idx->pack->idx_cache, &pentry->sha1)) {
+ git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", git_oid_tostr_s(&pentry->sha1));
git__free(pentry);
- git_error_set_oom();
goto on_error;
}
- if (error == 0) {
- git_error_set(GIT_ERROR_INDEXER, "duplicate object %s found in pack", git_oid_tostr_s(&pentry->sha1));
+ if ((error = git_oidmap_set(idx->pack->idx_cache, &pentry->sha1, pentry)) < 0) {
git__free(pentry);
+ git_error_set_oom();
goto on_error;
}
-
- git_oidmap_set_value_at(idx->pack->idx_cache, k, pentry);
-
git_oid_cpy(&entry->oid, &oid);
if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0)
return git_oidmap_exists(idx->pack->idx_cache, id);
}
-static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, git_off_t entry_start)
+static int save_entry(git_indexer *idx, struct entry *entry, struct git_pack_entry *pentry, off64_t entry_start)
{
- int i, error;
- size_t k;
+ int i;
if (entry_start > UINT31_MAX) {
entry->offset = UINT32_MAX;
}
pentry->offset = entry_start;
- k = git_oidmap_put(idx->pack->idx_cache, &pentry->sha1, &error);
- if (error <= 0) {
+ if (git_oidmap_exists(idx->pack->idx_cache, &pentry->sha1) ||
+ git_oidmap_set(idx->pack->idx_cache, &pentry->sha1, pentry) < 0) {
git_error_set(GIT_ERROR_INDEXER, "cannot insert object into pack");
return -1;
}
- git_oidmap_set_value_at(idx->pack->idx_cache, k, pentry);
-
/* Add the object to the list */
if (git_vector_insert(&idx->objects, entry) < 0)
return -1;
return 0;
}
-static int hash_and_save(git_indexer *idx, git_rawobj *obj, git_off_t entry_start)
+static int hash_and_save(git_indexer *idx, git_rawobj *obj, off64_t entry_start)
{
git_oid oid;
size_t entry_size;
return -1;
}
-static int do_progress_callback(git_indexer *idx, git_transfer_progress *stats)
+static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats)
{
if (idx->progress_cb)
return git_error_set_after_callback_function(
idx->inbuf_len += size - to_expell;
}
-static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t size)
+static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
{
git_file fd = idx->pack->mwf.fd;
size_t mmap_alignment;
size_t page_offset;
- git_off_t page_start;
+ off64_t page_start;
unsigned char *map_data;
git_map map;
int error;
static int append_to_pack(git_indexer *idx, const void *data, size_t size)
{
- git_off_t new_size;
+ off64_t new_size;
size_t mmap_alignment;
size_t page_offset;
- git_off_t page_start;
- git_off_t current_size = idx->pack->mwf.size;
+ off64_t page_start;
+ off64_t current_size = idx->pack->mwf.size;
int fd = idx->pack->mwf.fd;
int error;
return write_at(idx, data, idx->pack->mwf.size, size);
}
-static int read_stream_object(git_indexer *idx, git_transfer_progress *stats)
+static int read_stream_object(git_indexer *idx, git_indexer_progress *stats)
{
git_packfile_stream *stream = &idx->stream;
- git_off_t entry_start = idx->off;
+ off64_t entry_start = idx->off;
size_t entry_size;
git_object_t type;
git_mwindow *w = NULL;
return 0;
}
-int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_transfer_progress *stats)
+int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_indexer_progress *stats)
{
int error = -1;
struct git_pack_header *hdr = &idx->hdr;
return -1;
}
- idx->pack->idx_cache = git_oidmap_alloc();
- GIT_ERROR_CHECK_ALLOC(idx->pack->idx_cache);
+ if (git_oidmap_new(&idx->pack->idx_cache) < 0)
+ return -1;
idx->pack->has_cache = 1;
if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0)
git_oid foo = {{0}};
unsigned char hdr[64];
git_buf buf = GIT_BUF_INIT;
- git_off_t entry_start;
+ off64_t entry_start;
const void *data;
size_t len, hdr_len;
int error;
return error;
}
-static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
+static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats)
{
int error, found_ref_delta = 0;
unsigned int i;
size_t size;
git_object_t type;
git_mwindow *w = NULL;
- git_off_t curpos = 0;
+ off64_t curpos = 0;
unsigned char *base_info;
unsigned int left = 0;
git_oid base;
return 0;
}
-static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
+static int resolve_deltas(git_indexer *idx, git_indexer_progress *stats)
{
unsigned int i;
int error;
return 0;
}
-static int update_header_and_rehash(git_indexer *idx, git_transfer_progress *stats)
+static int update_header_and_rehash(git_indexer *idx, git_indexer_progress *stats)
{
void *ptr;
size_t chunk = 1024*1024;
- git_off_t hashed = 0;
+ off64_t hashed = 0;
git_mwindow *w = NULL;
git_mwindow_file *mwf;
unsigned int left;
return 0;
}
-int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
+int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
{
git_mwindow *w = NULL;
unsigned int i, long_offsets = 0, left;
void git_indexer_free(git_indexer *idx)
{
- size_t pos;
+ const git_oid *key;
+ git_oid *value;
+ size_t iter;
if (idx == NULL)
return;
git_mutex_unlock(&git__mwindow_mutex);
}
- for (pos = git_oidmap_begin(idx->expected_oids);
- pos != git_oidmap_end(idx->expected_oids); pos++)
- {
- if (git_oidmap_has_data(idx->expected_oids, pos)) {
- git__free((git_oid *) git_oidmap_key(idx->expected_oids, pos));
- git_oidmap_delete_at(idx->expected_oids, pos);
- }
- }
+ iter = 0;
+ while (git_oidmap_iterate((void **) &value, idx->expected_oids, &iter, &key) == 0)
+ git__free(value);
git_hash_ctx_cleanup(&idx->trailer);
git_hash_ctx_cleanup(&idx->hash_ctx);
#define INCLUDE_integer_h__
/** @return true if p fits into the range of a size_t */
-GIT_INLINE(int) git__is_sizet(git_off_t p)
+GIT_INLINE(int) git__is_sizet(int64_t p)
{
size_t r = (size_t)p;
- return p == (git_off_t)r;
+ return p == (int64_t)r;
}
/** @return true if p fits into the range of an ssize_t */
return p == (size_t)r;
}
+/** @return true if p fits into the range of a uint16_t */
+GIT_INLINE(int) git__is_uint16(size_t p)
+{
+ uint16_t r = (uint16_t)p;
+ return p == (size_t)r;
+}
+
/** @return true if p fits into the range of a uint32_t */
GIT_INLINE(int) git__is_uint32(size_t p)
{
}
/** @return true if p fits into the range of an unsigned long */
-GIT_INLINE(int) git__is_ulong(git_off_t p)
+GIT_INLINE(int) git__is_ulong(int64_t p)
{
unsigned long r = (unsigned long)p;
- return p == (git_off_t)r;
+ return p == (int64_t)r;
}
/** @return true if p fits into the range of an int */
# error compiler has add with overflow intrinsics but SIZE_MAX is unknown
# endif
+# define git__add_int_overflow(out, one, two) \
+ __builtin_sadd_overflow(one, two, out)
+# define git__sub_int_overflow(out, one, two) \
+ __builtin_ssub_overflow(one, two, out)
+
/* Use Microsoft's safe integer handling functions where available */
#elif defined(_MSC_VER)
+# define ENABLE_INTSAFE_SIGNED_FUNCTIONS
# include <intsafe.h>
# define git__add_sizet_overflow(out, one, two) \
(SizeTAdd(one, two, out) != S_OK)
# define git__multiply_sizet_overflow(out, one, two) \
(SizeTMult(one, two, out) != S_OK)
+#define git__add_int_overflow(out, one, two) \
+ (IntAdd(one, two, out) != S_OK)
+#define git__sub_int_overflow(out, one, two) \
+ (IntSub(one, two, out) != S_OK)
#else
return false;
}
+GIT_INLINE(bool) git__add_int_overflow(int *out, int one, int two)
+{
+ if ((two > 0 && one > (INT_MAX - two)) ||
+ (two < 0 && one < (INT_MIN - two)))
+ return true;
+ *out = one + two;
+ return false;
+}
+
+GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two)
+{
+ if ((two > 0 && one < (INT_MIN + two)) ||
+ (two < 0 && one > (INT_MAX + two)))
+ return true;
+ *out = one - two;
+ return false;
+}
+
#endif
#endif
(iter->flags & GIT_ITERATOR_PRECOMPOSE_UNICODE) == 0 &&
(iter->flags & GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE) == 0) {
- if (git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) < 0)
+ if (git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) < 0)
git_error_clear();
else if (precompose)
iter->flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
iter = git__calloc(1, sizeof(empty_iterator));
GIT_ERROR_CHECK_ALLOC(iter);
- iter->base.type = GIT_ITERATOR_TYPE_EMPTY;
+ iter->base.type = GIT_ITERATOR_EMPTY;
iter->base.cb = &callbacks;
iter->base.flags = options->flags;
new_frame = git_array_alloc(iter->frames);
GIT_ERROR_CHECK_ALLOC(new_frame);
- memset(new_frame, 0, sizeof(tree_iterator_frame));
-
if ((error = git_tree_dup(&dup, tree)) < 0)
goto done;
new_frame->tree = dup;
if (frame_entry &&
- (error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
+ (error = tree_iterator_compute_path(&new_frame->path, frame_entry)) < 0)
goto done;
cmp = iterator__ignore_case(&iter->base) ?
tree_iterator_entry_sort_icase : NULL;
- if ((error = git_vector_init(
- &new_frame->entries, dup->entries.size, cmp)) < 0)
+ if ((error = git_vector_init(&new_frame->entries,
+ dup->entries.size, cmp)) < 0)
goto done;
git_array_foreach(dup->entries, i, tree_entry) {
- new_entry = git_pool_malloc(&iter->entry_pool, 1);
- GIT_ERROR_CHECK_ALLOC(new_entry);
+ if ((new_entry = git_pool_malloc(&iter->entry_pool, 1)) == NULL) {
+ git_error_set_oom();
+ error = -1;
+ goto done;
+ }
new_entry->tree_entry = tree_entry;
new_entry->parent_path = new_frame->path.ptr;
{
int error;
- git_pool_init(&iter->entry_pool, sizeof(tree_iterator_entry));
-
- if ((error = tree_iterator_frame_init(iter, iter->root, NULL)) < 0)
+ if ((error = git_pool_init(&iter->entry_pool, sizeof(tree_iterator_entry))) < 0 ||
+ (error = tree_iterator_frame_init(iter, iter->root, NULL)) < 0)
return error;
iter->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
iter = git__calloc(1, sizeof(tree_iterator));
GIT_ERROR_CHECK_ALLOC(iter);
- iter->base.type = GIT_ITERATOR_TYPE_TREE;
+ iter->base.type = GIT_ITERATOR_TREE;
iter->base.cb = &callbacks;
if ((error = iterator_init_common(&iter->base,
tree_iterator_frame *frame;
tree_iterator_entry *entry;
- assert(i->type == GIT_ITERATOR_TYPE_TREE);
+ assert(i->type == GIT_ITERATOR_TREE);
iter = (tree_iterator *)i;
tree_iterator *iter;
tree_iterator_frame *frame;
- assert(i->type == GIT_ITERATOR_TYPE_TREE);
+ assert(i->type == GIT_ITERATOR_TREE);
iter = (tree_iterator *)i;
return 0;
}
- if (iter->base.type == GIT_ITERATOR_TYPE_WORKDIR)
+ if (iter->base.type == GIT_ITERATOR_WORKDIR)
return git_repository_hashfile(&entry->id,
iter->base.repo, entry->path, GIT_OBJECT_BLOB, NULL);
filesystem_iterator_entry_cmp)) < 0)
goto done;
- git_pool_init(&new_frame->entry_pool, 1);
+ if ((error = git_pool_init(&new_frame->entry_pool, 1)) < 0)
+ goto done;
/* check if this directory is ignored */
filesystem_iterator_frame_push_ignores(iter, frame_entry, new_frame);
static int filesystem_iterator_current(
const git_index_entry **out, git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
if (!iterator__has_been_accessed(i))
return iter->base.cb->advance(out, i);
static int filesystem_iterator_advance(
const git_index_entry **out, git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
bool is_dir;
int error = 0;
static int filesystem_iterator_advance_into(
const git_index_entry **out, git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
filesystem_iterator_frame *frame;
filesystem_iterator_entry *prev_entry;
int error;
int git_iterator_current_workdir_path(git_buf **out, git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
const git_index_entry *entry;
- if (i->type != GIT_ITERATOR_TYPE_FS &&
- i->type != GIT_ITERATOR_TYPE_WORKDIR) {
+ if (i->type != GIT_ITERATOR_FS &&
+ i->type != GIT_ITERATOR_WORKDIR) {
*out = NULL;
return 0;
}
bool git_iterator_current_is_ignored(git_iterator *i)
{
- if (i->type != GIT_ITERATOR_TYPE_WORKDIR)
+ filesystem_iterator *iter = NULL;
+
+ if (i->type != GIT_ITERATOR_WORKDIR)
return false;
- return filesystem_iterator_current_is_ignored((filesystem_iterator *)i);
+ iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
+
+ return filesystem_iterator_current_is_ignored(iter);
}
bool git_iterator_current_tree_is_ignored(git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
filesystem_iterator_frame *frame;
- if (i->type != GIT_ITERATOR_TYPE_WORKDIR)
+ if (i->type != GIT_ITERATOR_WORKDIR)
return false;
frame = filesystem_iterator_current_frame(iter);
git_iterator_status_t *status,
git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
filesystem_iterator_frame *current_frame;
filesystem_iterator_entry *current_entry;
const git_index_entry *entry = NULL;
static int filesystem_iterator_reset(git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
filesystem_iterator_clear(iter);
return filesystem_iterator_init(iter);
static void filesystem_iterator_free(git_iterator *i)
{
- filesystem_iterator *iter = (filesystem_iterator *)i;
+ filesystem_iterator *iter = GIT_CONTAINER_OF(i, filesystem_iterator, base);
git__free(iter->root);
git_buf_dispose(&iter->current_path);
git_tree_free(iter->tree);
const char *root,
git_index *index,
git_tree *tree,
- git_iterator_type_t type,
+ git_iterator_t type,
git_iterator_options *options)
{
filesystem_iterator *iter;
git_iterator_options *options)
{
return iterator_for_filesystem(out,
- NULL, root, NULL, NULL, GIT_ITERATOR_TYPE_FS, options);
+ NULL, root, NULL, NULL, GIT_ITERATOR_FS, options);
}
int git_iterator_for_workdir_ext(
GIT_ITERATOR_IGNORE_DOT_GIT;
return iterator_for_filesystem(out,
- repo, repo_workdir, index, tree, GIT_ITERATOR_TYPE_WORKDIR, &options);
+ repo, repo_workdir, index, tree, GIT_ITERATOR_WORKDIR, &options);
}
static int index_iterator_advance(
const git_index_entry **out, git_iterator *i)
{
- index_iterator *iter = (index_iterator *)i;
+ index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base);
const git_index_entry *entry = NULL;
bool is_submodule;
int error = 0;
static int index_iterator_advance_into(
const git_index_entry **out, git_iterator *i)
{
- index_iterator *iter = (index_iterator *)i;
+ index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base);
if (! S_ISDIR(iter->tree_entry.mode)) {
if (out)
git_iterator_status_t *status,
git_iterator *i)
{
- index_iterator *iter = (index_iterator *)i;
+ index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base);
const git_index_entry *entry;
int error;
static int index_iterator_reset(git_iterator *i)
{
- index_iterator *iter = (index_iterator *)i;
+ index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base);
index_iterator_clear(iter);
return index_iterator_init(iter);
static void index_iterator_free(git_iterator *i)
{
- index_iterator *iter = (index_iterator *)i;
+ index_iterator *iter = GIT_CONTAINER_OF(i, index_iterator, base);
git_index_snapshot_release(&iter->entries, iter->base.index);
git_buf_dispose(&iter->tree_buf);
iter = git__calloc(1, sizeof(index_iterator));
GIT_ERROR_CHECK_ALLOC(iter);
- iter->base.type = GIT_ITERATOR_TYPE_INDEX;
+ iter->base.type = GIT_ITERATOR_INDEX;
iter->base.cb = &callbacks;
if ((error = iterator_init_common(&iter->base, repo, index, options)) < 0 ||
typedef struct git_iterator git_iterator;
typedef enum {
- GIT_ITERATOR_TYPE_EMPTY = 0,
- GIT_ITERATOR_TYPE_TREE = 1,
- GIT_ITERATOR_TYPE_INDEX = 2,
- GIT_ITERATOR_TYPE_WORKDIR = 3,
- GIT_ITERATOR_TYPE_FS = 4,
-} git_iterator_type_t;
+ GIT_ITERATOR_EMPTY = 0,
+ GIT_ITERATOR_TREE = 1,
+ GIT_ITERATOR_INDEX = 2,
+ GIT_ITERATOR_WORKDIR = 3,
+ GIT_ITERATOR_FS = 4,
+} git_iterator_t;
typedef enum {
/** ignore case for entry sort order */
} git_iterator_callbacks;
struct git_iterator {
- git_iterator_type_t type;
+ git_iterator_t type;
git_iterator_callbacks *cb;
git_repository *repo;
extern int git_iterator_reset_range(
git_iterator *iter, const char *start, const char *end);
-GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter)
+GIT_INLINE(git_iterator_t) git_iterator_type(git_iterator *iter)
{
return iter->type;
}
assert((prot & GIT_PROT_WRITE) || (prot & GIT_PROT_READ)); \
assert((flags & GIT_MAP_FIXED) == 0); } while (0)
-extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset);
+extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset);
extern int p_munmap(git_map *map);
#endif
git_merge_diff *prev_conflict;
};
+/*
+ * This acts as a negative cache entry marker. In case we've tried to calculate
+ * similarity metrics for a given blob already but `git_hashsig` determined
+ * that it's too small in order to have a meaningful hash signature, we will
+ * insert the address of this marker instead of `NULL`. Like this, we can
+ * easily check whether we have checked a gien entry already and skip doing the
+ * calculation again and again.
+ */
+static int cache_invalid_marker;
+
/* Merge base computation */
-int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, size_t length, const git_oid input_array[])
+static int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, size_t length, const git_oid input_array[])
{
git_revwalk *walk = NULL;
git_vector list;
return 0;
}
-static void clear_commit_marks_1(git_commit_list **plist,
+static int clear_commit_marks_1(git_commit_list **plist,
git_commit_list_node *commit, unsigned int mark)
{
while (commit) {
unsigned int i;
if (!(mark & commit->flags))
- return;
+ return 0;
commit->flags &= ~mark;
for (i = 1; i < commit->out_degree; i++) {
git_commit_list_node *p = commit->parents[i];
- git_commit_list_insert(p, plist);
+ if (git_commit_list_insert(p, plist) == NULL)
+ return -1;
}
commit = commit->out_degree ? commit->parents[0] : NULL;
}
+
+ return 0;
}
-static void clear_commit_marks_many(git_vector *commits, unsigned int mark)
+static int clear_commit_marks_many(git_vector *commits, unsigned int mark)
{
git_commit_list *list = NULL;
git_commit_list_node *c;
unsigned int i;
git_vector_foreach(commits, i, c) {
- git_commit_list_insert(c, &list);
+ if (git_commit_list_insert(c, &list) == NULL)
+ return -1;
}
while (list)
- clear_commit_marks_1(&list, git_commit_list_pop(&list), mark);
+ if (clear_commit_marks_1(&list, git_commit_list_pop(&list), mark) < 0)
+ return -1;
+ return 0;
}
-static void clear_commit_marks(git_commit_list_node *commit, unsigned int mark)
+static int clear_commit_marks(git_commit_list_node *commit, unsigned int mark)
{
git_commit_list *list = NULL;
- git_commit_list_insert(commit, &list);
+ if (git_commit_list_insert(commit, &list) == NULL)
+ return -1;
while (list)
- clear_commit_marks_1(&list, git_commit_list_pop(&list), mark);
+ if (clear_commit_marks_1(&list, git_commit_list_pop(&list), mark) < 0)
+ return -1;
+ return 0;
}
static int paint_down_to_common(
redundant[filled_index[j]] = 1;
}
- clear_commit_marks(commit, ALL_FLAGS);
- clear_commit_marks_many(&work, ALL_FLAGS);
-
git_commit_list_free(&common);
+
+ if ((error = clear_commit_marks(commit, ALL_FLAGS)) < 0 ||
+ (error = clear_commit_marks_many(&work, ALL_FLAGS)) < 0)
+ goto done;
}
for (i = 0; i < commits->length; ++i) {
while (result)
git_vector_insert(&redundant, git_commit_list_pop(&result));
- clear_commit_marks(one, ALL_FLAGS);
- clear_commit_marks_many(twos, ALL_FLAGS);
-
- if ((error = remove_redundant(walk, &redundant)) < 0) {
+ if ((error = clear_commit_marks(one, ALL_FLAGS)) < 0 ||
+ (error = clear_commit_marks_many(twos, ALL_FLAGS)) < 0 ||
+ (error = remove_redundant(walk, &redundant)) < 0) {
git_vector_free(&redundant);
return error;
}
git_oid_cpy(&result->id, &oid);
result->mode = mode;
- result->file_size = buf.size;
+ result->file_size = (uint32_t)buf.size;
result->path = git_pool_strdup(&diff_list->pool, path);
GIT_ERROR_CHECK_ALLOC(result->path);
{
git_blob *blob;
git_diff_file diff_file = {{{0}}};
- git_off_t blobsize;
+ git_object_size_t blobsize;
int error;
+ if (*out || *out == &cache_invalid_marker)
+ return 0;
+
*out = NULL;
if ((error = git_blob_lookup(&blob, repo, &entry->id)) < 0)
error = opts->metric->buffer_signature(out, &diff_file,
git_blob_rawcontent(blob), (size_t)blobsize,
opts->metric->payload);
+ if (error == GIT_EBUFS)
+ *out = &cache_invalid_marker;
git_blob_free(blob);
return 0;
/* update signature cache if needed */
- if (!cache[a_idx] && (error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0)
- return error;
- if (!cache[b_idx] && (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0)
+ if ((error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0 ||
+ (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0)
return error;
/* some metrics may not wish to process this file (too big / too small) */
- if (!cache[a_idx] || !cache[b_idx])
+ if (cache[a_idx] == &cache_invalid_marker || cache[b_idx] == &cache_invalid_marker)
return 0;
/* compare signatures */
- if (opts->metric->similarity(
- &score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0)
+ if (opts->metric->similarity(&score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0)
return -1;
/* clip score */
git_oidmap_free(map);
}
-static int deletes_by_oid_enqueue(git_oidmap *map, git_pool* pool, const git_oid *id, size_t idx) {
- size_t pos;
+static int deletes_by_oid_enqueue(git_oidmap *map, git_pool* pool, const git_oid *id, size_t idx)
+{
deletes_by_oid_queue *queue;
size_t *array_entry;
- int error;
- pos = git_oidmap_lookup_index(map, id);
- if (!git_oidmap_valid_index(map, pos)) {
+ if ((queue = git_oidmap_get(map, id)) == NULL) {
queue = git_pool_malloc(pool, sizeof(deletes_by_oid_queue));
GIT_ERROR_CHECK_ALLOC(queue);
queue->next_pos = 0;
queue->first_entry = idx;
- git_oidmap_insert(map, id, queue, &error);
- if (error < 0)
+ if (git_oidmap_set(map, id, queue) < 0)
return -1;
} else {
- queue = git_oidmap_value_at(map, pos);
array_entry = git_array_alloc(queue->arr);
GIT_ERROR_CHECK_ALLOC(array_entry);
*array_entry = idx;
return 0;
}
-static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id) {
- size_t pos;
+static int deletes_by_oid_dequeue(size_t *idx, git_oidmap *map, const git_oid *id)
+{
deletes_by_oid_queue *queue;
size_t *array_entry;
- pos = git_oidmap_lookup_index(map, id);
-
- if (!git_oidmap_valid_index(map, pos))
+ if ((queue = git_oidmap_get(map, id)) == NULL)
return GIT_ENOTFOUND;
- queue = git_oidmap_value_at(map, pos);
-
if (queue->next_pos == 0) {
*idx = queue->first_entry;
} else {
git_oidmap *ours_deletes_by_oid = NULL, *theirs_deletes_by_oid = NULL;
int error = 0;
- if (!(ours_deletes_by_oid = git_oidmap_alloc()) ||
- !(theirs_deletes_by_oid = git_oidmap_alloc())) {
+ if (git_oidmap_new(&ours_deletes_by_oid) < 0 ||
+ git_oidmap_new(&theirs_deletes_by_oid) < 0) {
error = -1;
goto done;
}
done:
if (cache != NULL) {
for (i = 0; i < cache_size; ++i) {
- if (cache[i] != NULL)
+ if (cache[i] != NULL && cache[i] != &cache_invalid_marker)
opts->metric->free_signature(cache[i], opts->metric->payload);
}
diff_list->repo = repo;
- git_pool_init(&diff_list->pool, 1);
- if (git_vector_init(&diff_list->staged, 0, NULL) < 0 ||
- git_vector_init(&diff_list->conflicts, 0, NULL) < 0 ||
- git_vector_init(&diff_list->resolved, 0, NULL) < 0) {
- git_merge_diff_list__free(diff_list);
+ if (git_pool_init(&diff_list->pool, 1) < 0 ||
+ git_vector_init(&diff_list->staged, 0, NULL) < 0 ||
+ git_vector_init(&diff_list->conflicts, 0, NULL) < 0 ||
+ git_vector_init(&diff_list->resolved, 0, NULL) < 0) {
+ git_merge_diff_list__free(diff_list);
return NULL;
}
assert(repo && heads);
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_HEAD_FILE)) < 0 ||
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0)
goto cleanup;
for (i = 0; i < heads_len; i++) {
assert(repo);
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MODE_FILE)) < 0 ||
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0)
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0)
goto cleanup;
if ((error = git_filebuf_write(&file, "no-ff", 5)) < 0)
entries[i].merge_head = heads[i];
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) < 0 ||
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0 ||
(error = git_filebuf_write(&file, "Merge ", 6)) < 0)
goto cleanup;
return error;
}
-const char *merge_their_label(const char *branchname)
+static const char *merge_their_label(const char *branchname)
{
const char *slash;
*ancestor_head_out = NULL;
*our_head_out = NULL;
- if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
- goto done;
-
if ((error = git_annotated_commit_from_ref(&our_head, repo, our_ref)) < 0)
goto done;
return error;
}
-int git_merge_init_options(git_merge_options *opts, unsigned int version)
+int git_merge_options_init(git_merge_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT);
return 0;
}
-int git_merge_file_init_input(git_merge_file_input *input, unsigned int version)
+#ifndef GIT_DEPRECATE_HARD
+int git_merge_init_options(git_merge_options *opts, unsigned int version)
+{
+ return git_merge_options_init(opts, version);
+}
+#endif
+
+int git_merge_file_input_init(git_merge_file_input *input, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT);
return 0;
}
-int git_merge_file_init_options(
+#ifndef GIT_DEPRECATE_HARD
+int git_merge_file_init_input(git_merge_file_input *input, unsigned int version)
+{
+ return git_merge_file_input_init(input, version);
+}
+#endif
+
+int git_merge_file_options_init(
git_merge_file_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_merge_file_init_options(
+ git_merge_file_options *opts, unsigned int version)
+{
+ return git_merge_file_options_init(opts, version);
+}
+#endif
/* The child of a folder that is in a directory/file conflict. */
GIT_MERGE_DIFF_DF_CHILD = (1 << 11),
-} git_merge_diff_type_t;
+} git_merge_diff_t;
typedef struct {
git_repository *repo;
* Description of changes to one file across three trees.
*/
typedef struct {
- git_merge_diff_type_t type;
+ git_merge_diff_t type;
git_index_entry ancestor_entry;
static void git_merge_driver_global_shutdown(void);
-const git_repository* git_merge_driver_source_repo(const git_merge_driver_source *src)
+git_repository* git_merge_driver_source_repo(const git_merge_driver_source *src)
{
assert(src);
return src->repo;
return error;
/* set: use the built-in 3-way merge driver ("text") */
- if (GIT_ATTR_TRUE(value))
+ if (GIT_ATTR_IS_TRUE(value))
*out = merge_driver_name__text;
/* unset: do not merge ("binary") */
- else if (GIT_ATTR_FALSE(value))
+ else if (GIT_ATTR_IS_FALSE(value))
*out = merge_driver_name__binary;
- else if (GIT_ATTR_UNSPECIFIED(value) && default_driver)
+ else if (GIT_ATTR_IS_UNSPECIFIED(value) && default_driver)
*out = default_driver;
- else if (GIT_ATTR_UNSPECIFIED(value))
+ else if (GIT_ATTR_IS_UNSPECIFIED(value))
*out = merge_driver_name__text;
else
#include "repository.h"
#include "posix.h"
-#include "fileops.h"
+#include "futils.h"
#include "index.h"
#include "diff_xdiff.h"
#include "merge.h"
#define GIT_MERGE_FILE_SIDE_EXISTS(X) ((X)->mode != 0)
-int git_merge_file__input_from_index(
+static int merge_file_input_from_index(
git_merge_file_input *input_out,
git_odb_object **odb_object_out,
git_odb *odb,
goto done;
if (ancestor) {
- if ((error = git_merge_file__input_from_index(
+ if ((error = merge_file_input_from_index(
&ancestor_input, &odb_object[0], odb, ancestor)) < 0)
goto done;
ancestor_ptr = &ancestor_input;
}
- if ((error = git_merge_file__input_from_index(
- &our_input, &odb_object[1], odb, ours)) < 0 ||
- (error = git_merge_file__input_from_index(
- &their_input, &odb_object[2], odb, theirs)) < 0)
+ if ((error = merge_file_input_from_index(&our_input, &odb_object[1], odb, ours)) < 0 ||
+ (error = merge_file_input_from_index(&their_input, &odb_object[2], odb, theirs)) < 0)
goto done;
error = merge_file__from_inputs(out,
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "midx.h"
+
+#include "buffer.h"
+#include "futils.h"
+#include "hash.h"
+#include "odb.h"
+#include "pack.h"
+
+#define GIT_MIDX_FILE_MODE 0444
+
+#define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
+#define MIDX_VERSION 1
+#define MIDX_OBJECT_ID_VERSION 1
+struct git_midx_header {
+ uint32_t signature;
+ uint8_t version;
+ uint8_t object_id_version;
+ uint8_t chunks;
+ uint8_t base_midx_files;
+ uint32_t packfiles;
+};
+
+#define MIDX_PACKFILE_NAMES_ID 0x504e414d /* "PNAM" */
+#define MIDX_OID_FANOUT_ID 0x4f494446 /* "OIDF" */
+#define MIDX_OID_LOOKUP_ID 0x4f49444c /* "OIDL" */
+#define MIDX_OBJECT_OFFSETS_ID 0x4f4f4646 /* "OOFF" */
+#define MIDX_OBJECT_LARGE_OFFSETS_ID 0x4c4f4646 /* "LOFF" */
+
+struct git_midx_chunk {
+ off64_t offset;
+ size_t length;
+};
+
+static int midx_error(const char *message)
+{
+ git_error_set(GIT_ERROR_ODB, "invalid multi-pack-index file - %s", message);
+ return -1;
+}
+
+static int midx_parse_packfile_names(
+ git_midx_file *idx,
+ const unsigned char *data,
+ uint32_t packfiles,
+ struct git_midx_chunk *chunk)
+{
+ int error;
+ uint32_t i;
+ char *packfile_name = (char *)(data + chunk->offset);
+ size_t chunk_size = chunk->length, len;
+ if (chunk->offset == 0)
+ return midx_error("missing Packfile Names chunk");
+ if (chunk->length == 0)
+ return midx_error("empty Packfile Names chunk");
+ if ((error = git_vector_init(&idx->packfile_names, packfiles, git__strcmp_cb)) < 0)
+ return error;
+ for (i = 0; i < packfiles; ++i) {
+ len = p_strnlen(packfile_name, chunk_size);
+ if (len == 0)
+ return midx_error("empty packfile name");
+ if (len + 1 > chunk_size)
+ return midx_error("unterminated packfile name");
+ git_vector_insert(&idx->packfile_names, packfile_name);
+ if (i && strcmp(git_vector_get(&idx->packfile_names, i - 1), packfile_name) >= 0)
+ return midx_error("packfile names are not sorted");
+ if (strlen(packfile_name) <= strlen(".idx") || git__suffixcmp(packfile_name, ".idx") != 0)
+ return midx_error("non-.idx packfile name");
+ if (strchr(packfile_name, '/') != NULL || strchr(packfile_name, '\\') != NULL)
+ return midx_error("non-local packfile");
+ packfile_name += len + 1;
+ chunk_size -= len + 1;
+ }
+ return 0;
+}
+
+static int midx_parse_oid_fanout(
+ git_midx_file *idx,
+ const unsigned char *data,
+ struct git_midx_chunk *chunk_oid_fanout)
+{
+ uint32_t i, nr;
+ if (chunk_oid_fanout->offset == 0)
+ return midx_error("missing OID Fanout chunk");
+ if (chunk_oid_fanout->length == 0)
+ return midx_error("empty OID Fanout chunk");
+ if (chunk_oid_fanout->length != 256 * 4)
+ return midx_error("OID Fanout chunk has wrong length");
+
+ idx->oid_fanout = (const uint32_t *)(data + chunk_oid_fanout->offset);
+ nr = 0;
+ for (i = 0; i < 256; ++i) {
+ uint32_t n = ntohl(idx->oid_fanout[i]);
+ if (n < nr)
+ return midx_error("index is non-monotonic");
+ nr = n;
+ }
+ idx->num_objects = nr;
+ return 0;
+}
+
+static int midx_parse_oid_lookup(
+ git_midx_file *idx,
+ const unsigned char *data,
+ struct git_midx_chunk *chunk_oid_lookup)
+{
+ uint32_t i;
+ git_oid *oid, *prev_oid, zero_oid = {{0}};
+
+ if (chunk_oid_lookup->offset == 0)
+ return midx_error("missing OID Lookup chunk");
+ if (chunk_oid_lookup->length == 0)
+ return midx_error("empty OID Lookup chunk");
+ if (chunk_oid_lookup->length != idx->num_objects * 20)
+ return midx_error("OID Lookup chunk has wrong length");
+
+ idx->oid_lookup = oid = (git_oid *)(data + chunk_oid_lookup->offset);
+ prev_oid = &zero_oid;
+ for (i = 0; i < idx->num_objects; ++i, ++oid) {
+ if (git_oid_cmp(prev_oid, oid) >= 0)
+ return midx_error("OID Lookup index is non-monotonic");
+ prev_oid = oid;
+ }
+
+ return 0;
+}
+
+static int midx_parse_object_offsets(
+ git_midx_file *idx,
+ const unsigned char *data,
+ struct git_midx_chunk *chunk_object_offsets)
+{
+ if (chunk_object_offsets->offset == 0)
+ return midx_error("missing Object Offsets chunk");
+ if (chunk_object_offsets->length == 0)
+ return midx_error("empty Object Offsets chunk");
+ if (chunk_object_offsets->length != idx->num_objects * 8)
+ return midx_error("Object Offsets chunk has wrong length");
+
+ idx->object_offsets = data + chunk_object_offsets->offset;
+
+ return 0;
+}
+
+static int midx_parse_object_large_offsets(
+ git_midx_file *idx,
+ const unsigned char *data,
+ struct git_midx_chunk *chunk_object_large_offsets)
+{
+ if (chunk_object_large_offsets->length == 0)
+ return 0;
+ if (chunk_object_large_offsets->length % 8 != 0)
+ return midx_error("malformed Object Large Offsets chunk");
+
+ idx->object_large_offsets = data + chunk_object_large_offsets->offset;
+ idx->num_object_large_offsets = chunk_object_large_offsets->length / 8;
+
+ return 0;
+}
+
+int git_midx_parse(
+ git_midx_file *idx,
+ const unsigned char *data,
+ size_t size)
+{
+ struct git_midx_header *hdr;
+ const unsigned char *chunk_hdr;
+ struct git_midx_chunk *last_chunk;
+ uint32_t i;
+ off64_t last_chunk_offset, chunk_offset, trailer_offset;
+ git_oid idx_checksum = {{0}};
+ int error;
+ struct git_midx_chunk chunk_packfile_names = {0},
+ chunk_oid_fanout = {0},
+ chunk_oid_lookup = {0},
+ chunk_object_offsets = {0},
+ chunk_object_large_offsets = {0};
+
+ assert(idx);
+
+ if (size < sizeof(struct git_midx_header) + 20)
+ return midx_error("multi-pack index is too short");
+
+ hdr = ((struct git_midx_header *)data);
+
+ if (hdr->signature != htonl(MIDX_SIGNATURE) ||
+ hdr->version != MIDX_VERSION ||
+ hdr->object_id_version != MIDX_OBJECT_ID_VERSION) {
+ return midx_error("unsupported multi-pack index version");
+ }
+ if (hdr->chunks == 0)
+ return midx_error("no chunks in multi-pack index");
+
+ /*
+ * The very first chunk's offset should be after the header, all the chunk
+ * headers, and a special zero chunk.
+ */
+ last_chunk_offset =
+ sizeof(struct git_midx_header) +
+ (1 + hdr->chunks) * 12;
+ trailer_offset = size - 20;
+ if (trailer_offset < last_chunk_offset)
+ return midx_error("wrong index size");
+ git_oid_cpy(&idx->checksum, (git_oid *)(data + trailer_offset));
+
+ if (git_hash_buf(&idx_checksum, data, (size_t)trailer_offset) < 0)
+ return midx_error("could not calculate signature");
+ if (!git_oid_equal(&idx_checksum, &idx->checksum))
+ return midx_error("index signature mismatch");
+
+ chunk_hdr = data + sizeof(struct git_midx_header);
+ last_chunk = NULL;
+ for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) {
+ chunk_offset = ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32 |
+ ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 8))));
+ if (chunk_offset < last_chunk_offset)
+ return midx_error("chunks are non-monotonic");
+ if (chunk_offset >= trailer_offset)
+ return midx_error("chunks extend beyond the trailer");
+ if (last_chunk != NULL)
+ last_chunk->length = (size_t)(chunk_offset - last_chunk_offset);
+ last_chunk_offset = chunk_offset;
+
+ switch (ntohl(*((uint32_t *)(chunk_hdr + 0)))) {
+ case MIDX_PACKFILE_NAMES_ID:
+ chunk_packfile_names.offset = last_chunk_offset;
+ last_chunk = &chunk_packfile_names;
+ break;
+
+ case MIDX_OID_FANOUT_ID:
+ chunk_oid_fanout.offset = last_chunk_offset;
+ last_chunk = &chunk_oid_fanout;
+ break;
+
+ case MIDX_OID_LOOKUP_ID:
+ chunk_oid_lookup.offset = last_chunk_offset;
+ last_chunk = &chunk_oid_lookup;
+ break;
+
+ case MIDX_OBJECT_OFFSETS_ID:
+ chunk_object_offsets.offset = last_chunk_offset;
+ last_chunk = &chunk_object_offsets;
+ break;
+
+ case MIDX_OBJECT_LARGE_OFFSETS_ID:
+ chunk_object_large_offsets.offset = last_chunk_offset;
+ last_chunk = &chunk_object_large_offsets;
+ break;
+
+ default:
+ return midx_error("unrecognized chunk ID");
+ }
+ }
+ last_chunk->length = (size_t)(trailer_offset - last_chunk_offset);
+
+ error = midx_parse_packfile_names(
+ idx, data, ntohl(hdr->packfiles), &chunk_packfile_names);
+ if (error < 0)
+ return error;
+ error = midx_parse_oid_fanout(idx, data, &chunk_oid_fanout);
+ if (error < 0)
+ return error;
+ error = midx_parse_oid_lookup(idx, data, &chunk_oid_lookup);
+ if (error < 0)
+ return error;
+ error = midx_parse_object_offsets(idx, data, &chunk_object_offsets);
+ if (error < 0)
+ return error;
+ error = midx_parse_object_large_offsets(idx, data, &chunk_object_large_offsets);
+ if (error < 0)
+ return error;
+
+ return 0;
+}
+
+int git_midx_open(
+ git_midx_file **idx_out,
+ const char *path)
+{
+ git_midx_file *idx;
+ git_file fd = -1;
+ size_t idx_size;
+ struct stat st;
+ int error;
+
+ /* TODO: properly open the file without access time using O_NOATIME */
+ fd = git_futils_open_ro(path);
+ if (fd < 0)
+ return fd;
+
+ if (p_fstat(fd, &st) < 0) {
+ p_close(fd);
+ git_error_set(GIT_ERROR_ODB, "multi-pack-index file not found - '%s'", path);
+ return -1;
+ }
+
+ if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size)) {
+ p_close(fd);
+ git_error_set(GIT_ERROR_ODB, "invalid pack index '%s'", path);
+ return -1;
+ }
+ idx_size = (size_t)st.st_size;
+
+ idx = git__calloc(1, sizeof(git_midx_file));
+ GIT_ERROR_CHECK_ALLOC(idx);
+
+ error = git_futils_mmap_ro(&idx->index_map, fd, 0, idx_size);
+ p_close(fd);
+ if (error < 0) {
+ git_midx_free(idx);
+ return error;
+ }
+
+ if ((error = git_midx_parse(idx, idx->index_map.data, idx_size)) < 0) {
+ git_midx_free(idx);
+ return error;
+ }
+
+ *idx_out = idx;
+ return 0;
+}
+
+int git_midx_entry_find(
+ git_midx_entry *e,
+ git_midx_file *idx,
+ const git_oid *short_oid,
+ size_t len)
+{
+ int pos, found = 0;
+ size_t pack_index;
+ uint32_t hi, lo;
+ const git_oid *current = NULL;
+ const unsigned char *object_offset;
+ off64_t offset;
+
+ assert(idx);
+
+ hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]);
+ lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1]));
+
+ pos = git_pack__lookup_sha1(idx->oid_lookup, 20, lo, hi, short_oid->id);
+
+ if (pos >= 0) {
+ /* An object matching exactly the oid was found */
+ found = 1;
+ current = idx->oid_lookup + pos;
+ } else {
+ /* No object was found */
+ /* pos refers to the object with the "closest" oid to short_oid */
+ pos = -1 - pos;
+ if (pos < (int)idx->num_objects) {
+ current = idx->oid_lookup + pos;
+
+ if (!git_oid_ncmp(short_oid, current, len))
+ found = 1;
+ }
+ }
+
+ if (found && len != GIT_OID_HEXSZ && pos + 1 < (int)idx->num_objects) {
+ /* Check for ambiguousity */
+ const git_oid *next = current + 1;
+
+ if (!git_oid_ncmp(short_oid, next, len)) {
+ found = 2;
+ }
+ }
+
+ if (!found)
+ return git_odb__error_notfound("failed to find offset for multi-pack index entry", short_oid, len);
+ if (found > 1)
+ return git_odb__error_ambiguous("found multiple offsets for multi-pack index entry");
+
+ object_offset = idx->object_offsets + pos * 8;
+ offset = ntohl(*((uint32_t *)(object_offset + 4)));
+ if (offset & 0x80000000) {
+ uint32_t object_large_offsets_pos = offset & 0x7fffffff;
+ const unsigned char *object_large_offsets_index = idx->object_large_offsets;
+
+ /* Make sure we're not being sent out of bounds */
+ if (object_large_offsets_pos >= idx->num_object_large_offsets)
+ return git_odb__error_notfound("invalid index into the object large offsets table", short_oid, len);
+
+ object_large_offsets_index += 8 * object_large_offsets_pos;
+
+ offset = (((uint64_t)ntohl(*((uint32_t *)(object_large_offsets_index + 0)))) << 32) |
+ ntohl(*((uint32_t *)(object_large_offsets_index + 4)));
+ }
+ pack_index = ntohl(*((uint32_t *)(object_offset + 0)));
+ if (pack_index >= git_vector_length(&idx->packfile_names))
+ return midx_error("invalid index into the packfile names table");
+ e->pack_index = pack_index;
+ e->offset = offset;
+ git_oid_cpy(&e->sha1, current);
+ return 0;
+}
+
+void git_midx_close(git_midx_file *idx)
+{
+ assert(idx);
+
+ if (idx->index_map.data)
+ git_futils_mmap_free(&idx->index_map);
+ git_vector_free(&idx->packfile_names);
+}
+
+void git_midx_free(git_midx_file *idx)
+{
+ if (!idx)
+ return;
+
+ git_midx_close(idx);
+ git__free(idx);
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_midx_h__
+#define INCLUDE_midx_h__
+
+#include "common.h"
+
+#include <ctype.h>
+
+#include "map.h"
+#include "mwindow.h"
+
+/*
+ * A multi-pack-index file.
+ *
+ * This file contains a merged index for multiple independent .pack files. This
+ * can help speed up locating objects without requiring a garbage collection
+ * cycle to create a single .pack file.
+ *
+ * Support for this feature was added in git 2.21, and requires the
+ * `core.multiPackIndex` config option to be set.
+ */
+typedef struct git_midx_file {
+ git_map index_map;
+
+ /* The table of Packfile Names. */
+ git_vector packfile_names;
+
+ /* The OID Fanout table. */
+ const uint32_t *oid_fanout;
+ /* The total number of objects in the index. */
+ uint32_t num_objects;
+
+ /* The OID Lookup table. */
+ git_oid *oid_lookup;
+
+ /* The Object Offsets table. Each entry has two 4-byte fields with the pack index and the offset. */
+ const unsigned char *object_offsets;
+
+ /* The Object Large Offsets table. */
+ const unsigned char *object_large_offsets;
+ /* The number of entries in the Object Large Offsets table. Each entry has an 8-byte with an offset */
+ size_t num_object_large_offsets;
+
+ /* The trailer of the file. Contains the SHA1-checksum of the whole file. */
+ git_oid checksum;
+} git_midx_file;
+
+/*
+ * An entry in the multi-pack-index file. Similar in purpose to git_pack_entry.
+ */
+typedef struct git_midx_entry {
+ /* The index within idx->packfile_names where the packfile name can be found. */
+ size_t pack_index;
+ /* The offset within the .pack file where the requested object is found. */
+ off64_t offset;
+ /* The SHA-1 hash of the requested object. */
+ git_oid sha1;
+} git_midx_entry;
+
+int git_midx_open(
+ git_midx_file **idx_out,
+ const char *path);
+int git_midx_entry_find(
+ git_midx_entry *e,
+ git_midx_file *idx,
+ const git_oid *short_oid,
+ size_t len);
+void git_midx_close(git_midx_file *idx);
+void git_midx_free(git_midx_file *idx);
+
+/* This is exposed for use in the fuzzers. */
+int git_midx_parse(
+ git_midx_file *idx,
+ const unsigned char *data,
+ size_t size);
+
+#endif
#include "mwindow.h"
#include "vector.h"
-#include "fileops.h"
+#include "futils.h"
#include "map.h"
#include "global.h"
#include "strmap.h"
#define DEFAULT_MAPPED_LIMIT \
((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
+/* default is unlimited */
+#define DEFAULT_FILE_LIMIT 0
+
size_t git_mwindow__window_size = DEFAULT_WINDOW_SIZE;
size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT;
+size_t git_mwindow__file_limit = DEFAULT_FILE_LIMIT;
/* Whenever you want to read or modify this, grab git__mwindow_mutex */
-static git_mwindow_ctl mem_ctl;
+git_mwindow_ctl git_mwindow__mem_ctl;
/* Global list of mwindow files, to open packs once across repos */
git_strmap *git__pack_cache = NULL;
assert(!git__pack_cache);
git__on_shutdown(git_mwindow_files_free);
- return git_strmap_alloc(&git__pack_cache);
+ return git_strmap_new(&git__pack_cache);
}
int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
{
- int error;
- char *packname;
- size_t pos;
struct git_pack_file *pack;
+ char *packname;
+ int error;
if ((error = git_packfile__name(&packname, path)) < 0)
return error;
return -1;
}
- pos = git_strmap_lookup_index(git__pack_cache, packname);
+ pack = git_strmap_get(git__pack_cache, packname);
git__free(packname);
- if (git_strmap_valid_index(git__pack_cache, pos)) {
- pack = git_strmap_value_at(git__pack_cache, pos);
+ if (pack != NULL) {
git_atomic_inc(&pack->refcount);
-
git_mutex_unlock(&git__mwindow_mutex);
*out = pack;
return 0;
git_atomic_inc(&pack->refcount);
- git_strmap_insert(git__pack_cache, pack->pack_name, pack, &error);
+ error = git_strmap_set(git__pack_cache, pack->pack_name, pack);
git_mutex_unlock(&git__mwindow_mutex);
if (error < 0) {
void git_mwindow_put_pack(struct git_pack_file *pack)
{
int count;
- size_t pos;
if (git_mutex_lock(&git__mwindow_mutex) < 0)
return;
/* put before get would be a corrupted state */
assert(git__pack_cache);
- pos = git_strmap_lookup_index(git__pack_cache, pack->pack_name);
/* if we cannot find it, the state is corrupted */
- assert(git_strmap_valid_index(git__pack_cache, pos));
+ assert(git_strmap_exists(git__pack_cache, pack->pack_name));
count = git_atomic_dec(&pack->refcount);
if (count == 0) {
- git_strmap_delete_at(git__pack_cache, pos);
+ git_strmap_delete(git__pack_cache, pack->pack_name);
git_packfile_free(pack);
}
*/
void git_mwindow_free_all_locked(git_mwindow_file *mwf)
{
- git_mwindow_ctl *ctl = &mem_ctl;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
size_t i;
/*
/*
* Check if a window 'win' contains the address 'offset'
*/
-int git_mwindow_contains(git_mwindow *win, git_off_t offset)
+int git_mwindow_contains(git_mwindow *win, off64_t offset)
{
- git_off_t win_off = win->offset;
+ off64_t win_off = win->offset;
return win_off <= offset
- && offset <= (git_off_t)(win_off + win->window_map.len);
+ && offset <= (off64_t)(win_off + win->window_map.len);
}
+#define GIT_MWINDOW__LRU -1
+#define GIT_MWINDOW__MRU 1
+
/*
- * Find the least-recently-used window in a file
+ * Find the least- or most-recently-used window in a file that is not currently
+ * being used. The 'only_unused' flag controls whether the caller requires the
+ * file to only have unused windows. If '*out_window' is non-null, it is used as
+ * a starting point for the comparison.
+ *
+ * Returns whether such a window was found in the file.
*/
-static void git_mwindow_scan_lru(
- git_mwindow_file *mwf,
- git_mwindow **lru_w,
- git_mwindow **lru_l)
+static bool git_mwindow_scan_recently_used(
+ git_mwindow_file *mwf,
+ git_mwindow **out_window,
+ git_mwindow **out_last,
+ bool only_unused,
+ int comparison_sign)
{
- git_mwindow *w, *w_l;
-
- for (w_l = NULL, w = mwf->windows; w; w = w->next) {
- if (!w->inuse_cnt) {
- /*
- * If the current one is more recent than the last one,
- * store it in the output parameter. If lru_w is NULL,
- * it's the first loop, so store it as well.
- */
- if (!*lru_w || w->last_used < (*lru_w)->last_used) {
- *lru_w = w;
- *lru_l = w_l;
- }
+ git_mwindow *w, *w_last;
+ git_mwindow *lru_window = NULL, *lru_last = NULL;
+ bool found = false;
+
+ assert(mwf);
+ assert(out_window);
+
+ lru_window = *out_window;
+ if (out_last)
+ lru_last = *out_last;
+
+ for (w_last = NULL, w = mwf->windows; w; w_last = w, w = w->next) {
+ if (w->inuse_cnt) {
+ if (only_unused)
+ return false;
+ /* This window is currently being used. Skip it. */
+ continue;
+ }
+
+ /*
+ * If the current one is more (or less) recent than the last one,
+ * store it in the output parameter. If lru_window is NULL,
+ * it's the first loop, so store it as well.
+ */
+ if (!lru_window ||
+ (comparison_sign == GIT_MWINDOW__LRU && lru_window->last_used > w->last_used) ||
+ (comparison_sign == GIT_MWINDOW__MRU && lru_window->last_used < w->last_used)) {
+ lru_window = w;
+ lru_last = w_last;
+ found = true;
}
- w_l = w;
}
+
+ if (!found)
+ return false;
+
+ *out_window = lru_window;
+ if (out_last)
+ *out_last = lru_last;
+ return true;
}
/*
- * Close the least recently used window. You should check to see if
- * the file descriptors need closing from time to time. Called under
- * lock from new_window.
+ * Close the least recently used window (that is currently not being used) out
+ * of all the files. Called under lock from new_window.
*/
-static int git_mwindow_close_lru(git_mwindow_file *mwf)
+static int git_mwindow_close_lru_window(void)
{
- git_mwindow_ctl *ctl = &mem_ctl;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
+ git_mwindow_file *cur;
size_t i;
- git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows;
-
- /* FIXME: Does this give us any advantage? */
- if(mwf->windows)
- git_mwindow_scan_lru(mwf, &lru_w, &lru_l);
+ git_mwindow *lru_window = NULL, *lru_last = NULL, **list = NULL;
- for (i = 0; i < ctl->windowfiles.length; ++i) {
- git_mwindow *last = lru_w;
- git_mwindow_file *cur = git_vector_get(&ctl->windowfiles, i);
- git_mwindow_scan_lru(cur, &lru_w, &lru_l);
- if (lru_w != last)
+ git_vector_foreach(&ctl->windowfiles, i, cur) {
+ if (git_mwindow_scan_recently_used(
+ cur, &lru_window, &lru_last, false, GIT_MWINDOW__LRU)) {
list = &cur->windows;
+ }
}
- if (!lru_w) {
+ if (!lru_window) {
git_error_set(GIT_ERROR_OS, "failed to close memory window; couldn't find LRU");
return -1;
}
- ctl->mapped -= lru_w->window_map.len;
- git_futils_mmap_free(&lru_w->window_map);
+ ctl->mapped -= lru_window->window_map.len;
+ git_futils_mmap_free(&lru_window->window_map);
- if (lru_l)
- lru_l->next = lru_w->next;
+ if (lru_last)
+ lru_last->next = lru_window->next;
else
- *list = lru_w->next;
+ *list = lru_window->next;
- git__free(lru_w);
+ git__free(lru_window);
ctl->open_windows--;
return 0;
}
+/*
+ * Close the file that does not have any open windows AND whose
+ * most-recently-used window is the least-recently used one across all
+ * currently open files.
+ *
+ * Called under lock from new_window.
+ */
+static int git_mwindow_close_lru_file(void)
+{
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
+ git_mwindow_file *lru_file = NULL, *current_file = NULL;
+ git_mwindow *lru_window = NULL;
+ size_t i;
+
+ git_vector_foreach(&ctl->windowfiles, i, current_file) {
+ git_mwindow *mru_window = NULL;
+ if (!git_mwindow_scan_recently_used(
+ current_file, &mru_window, NULL, true, GIT_MWINDOW__MRU)) {
+ continue;
+ }
+ if (!lru_window || lru_window->last_used > mru_window->last_used)
+ lru_file = current_file;
+ }
+
+ if (!lru_file) {
+ git_error_set(GIT_ERROR_OS, "failed to close memory window file; couldn't find LRU");
+ return -1;
+ }
+
+ git_mwindow_free_all_locked(lru_file);
+ p_close(lru_file->fd);
+ lru_file->fd = -1;
+
+ return 0;
+}
+
/* This gets called under lock from git_mwindow_open */
static git_mwindow *new_window(
- git_mwindow_file *mwf,
git_file fd,
- git_off_t size,
- git_off_t offset)
+ off64_t size,
+ off64_t offset)
{
- git_mwindow_ctl *ctl = &mem_ctl;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
size_t walign = git_mwindow__window_size / 2;
- git_off_t len;
+ off64_t len;
git_mwindow *w;
w = git__malloc(sizeof(*w));
w->offset = (offset / walign) * walign;
len = size - w->offset;
- if (len > (git_off_t)git_mwindow__window_size)
- len = (git_off_t)git_mwindow__window_size;
+ if (len > (off64_t)git_mwindow__window_size)
+ len = (off64_t)git_mwindow__window_size;
ctl->mapped += (size_t)len;
while (git_mwindow__mapped_limit < ctl->mapped &&
- git_mwindow_close_lru(mwf) == 0) /* nop */;
+ git_mwindow_close_lru_window() == 0) /* nop */;
/*
* We treat `mapped_limit` as a soft limit. If we can't find a
* we're below our soft limits, so free up what we can and try again.
*/
- while (git_mwindow_close_lru(mwf) == 0)
+ while (git_mwindow_close_lru_window() == 0)
/* nop */;
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) {
unsigned char *git_mwindow_open(
git_mwindow_file *mwf,
git_mwindow **cursor,
- git_off_t offset,
+ off64_t offset,
size_t extra,
unsigned int *left)
{
- git_mwindow_ctl *ctl = &mem_ctl;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
git_mwindow *w = *cursor;
if (git_mutex_lock(&git__mwindow_mutex)) {
* one.
*/
if (!w) {
- w = new_window(mwf, mwf->fd, mwf->size, offset);
+ w = new_window(mwf->fd, mwf->size, offset);
if (w == NULL) {
git_mutex_unlock(&git__mwindow_mutex);
return NULL;
int git_mwindow_file_register(git_mwindow_file *mwf)
{
- git_mwindow_ctl *ctl = &mem_ctl;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
int ret;
if (git_mutex_lock(&git__mwindow_mutex)) {
return -1;
}
+ if (git_mwindow__file_limit) {
+ while (git_mwindow__file_limit <= ctl->windowfiles.length &&
+ git_mwindow_close_lru_file() == 0) /* nop */;
+ }
+
ret = git_vector_insert(&ctl->windowfiles, mwf);
git_mutex_unlock(&git__mwindow_mutex);
void git_mwindow_file_deregister(git_mwindow_file *mwf)
{
- git_mwindow_ctl *ctl = &mem_ctl;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
git_mwindow_file *cur;
size_t i;
typedef struct git_mwindow {
struct git_mwindow *next;
git_map window_map;
- git_off_t offset;
+ off64_t offset;
size_t last_used;
size_t inuse_cnt;
} git_mwindow;
typedef struct git_mwindow_file {
git_mwindow *windows;
int fd;
- git_off_t size;
+ off64_t size;
} git_mwindow_file;
typedef struct git_mwindow_ctl {
git_vector windowfiles;
} git_mwindow_ctl;
-int git_mwindow_contains(git_mwindow *win, git_off_t offset);
+int git_mwindow_contains(git_mwindow *win, off64_t offset);
void git_mwindow_free_all(git_mwindow_file *mwf); /* locks */
void git_mwindow_free_all_locked(git_mwindow_file *mwf); /* run under lock */
-unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left);
+unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, off64_t offset, size_t extra, unsigned int *left);
int git_mwindow_file_register(git_mwindow_file *mwf);
void git_mwindow_file_deregister(git_mwindow_file *mwf);
void git_mwindow_close(git_mwindow **w_cursor);
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "net.h"
+#include "netops.h"
+
+#include <ctype.h>
+#include "git2/errors.h"
+
+#include "posix.h"
+#include "buffer.h"
+#include "http_parser.h"
+#include "global.h"
+
+#define DEFAULT_PORT_HTTP "80"
+#define DEFAULT_PORT_HTTPS "443"
+#define DEFAULT_PORT_GIT "9418"
+#define DEFAULT_PORT_SSH "22"
+
+static const char *default_port_for_scheme(const char *scheme)
+{
+ if (strcmp(scheme, "http") == 0)
+ return DEFAULT_PORT_HTTP;
+ else if (strcmp(scheme, "https") == 0)
+ return DEFAULT_PORT_HTTPS;
+ else if (strcmp(scheme, "git") == 0)
+ return DEFAULT_PORT_GIT;
+ else if (strcmp(scheme, "ssh") == 0)
+ return DEFAULT_PORT_SSH;
+
+ return NULL;
+}
+
+int git_net_url_parse(git_net_url *url, const char *given)
+{
+ struct http_parser_url u = {0};
+ bool has_scheme, has_host, has_port, has_path, has_query, has_userinfo;
+ git_buf scheme = GIT_BUF_INIT,
+ host = GIT_BUF_INIT,
+ port = GIT_BUF_INIT,
+ path = GIT_BUF_INIT,
+ username = GIT_BUF_INIT,
+ password = GIT_BUF_INIT,
+ query = GIT_BUF_INIT;
+ int error = GIT_EINVALIDSPEC;
+
+ if (http_parser_parse_url(given, strlen(given), false, &u)) {
+ git_error_set(GIT_ERROR_NET, "malformed URL '%s'", given);
+ goto done;
+ }
+
+ has_scheme = !!(u.field_set & (1 << UF_SCHEMA));
+ has_host = !!(u.field_set & (1 << UF_HOST));
+ has_port = !!(u.field_set & (1 << UF_PORT));
+ has_path = !!(u.field_set & (1 << UF_PATH));
+ has_query = !!(u.field_set & (1 << UF_QUERY));
+ has_userinfo = !!(u.field_set & (1 << UF_USERINFO));
+
+ if (has_scheme) {
+ const char *url_scheme = given + u.field_data[UF_SCHEMA].off;
+ size_t url_scheme_len = u.field_data[UF_SCHEMA].len;
+ git_buf_put(&scheme, url_scheme, url_scheme_len);
+ git__strntolower(scheme.ptr, scheme.size);
+ } else {
+ git_error_set(GIT_ERROR_NET, "malformed URL '%s'", given);
+ goto done;
+ }
+
+ if (has_host) {
+ const char *url_host = given + u.field_data[UF_HOST].off;
+ size_t url_host_len = u.field_data[UF_HOST].len;
+ git_buf_decode_percent(&host, url_host, url_host_len);
+ }
+
+ if (has_port) {
+ const char *url_port = given + u.field_data[UF_PORT].off;
+ size_t url_port_len = u.field_data[UF_PORT].len;
+ git_buf_put(&port, url_port, url_port_len);
+ } else {
+ const char *default_port = default_port_for_scheme(scheme.ptr);
+
+ if (default_port == NULL) {
+ git_error_set(GIT_ERROR_NET, "unknown scheme for URL '%s'", given);
+ goto done;
+ }
+
+ git_buf_puts(&port, default_port);
+ }
+
+ if (has_path) {
+ const char *url_path = given + u.field_data[UF_PATH].off;
+ size_t url_path_len = u.field_data[UF_PATH].len;
+ git_buf_put(&path, url_path, url_path_len);
+ } else {
+ git_buf_puts(&path, "/");
+ }
+
+ if (has_query) {
+ const char *url_query = given + u.field_data[UF_QUERY].off;
+ size_t url_query_len = u.field_data[UF_QUERY].len;
+ git_buf_decode_percent(&query, url_query, url_query_len);
+ }
+
+ if (has_userinfo) {
+ const char *url_userinfo = given + u.field_data[UF_USERINFO].off;
+ size_t url_userinfo_len = u.field_data[UF_USERINFO].len;
+ const char *colon = memchr(url_userinfo, ':', url_userinfo_len);
+
+ if (colon) {
+ const char *url_username = url_userinfo;
+ size_t url_username_len = colon - url_userinfo;
+ const char *url_password = colon + 1;
+ size_t url_password_len = url_userinfo_len - (url_username_len + 1);
+
+ git_buf_decode_percent(&username, url_username, url_username_len);
+ git_buf_decode_percent(&password, url_password, url_password_len);
+ } else {
+ git_buf_decode_percent(&username, url_userinfo, url_userinfo_len);
+ }
+ }
+
+ if (git_buf_oom(&scheme) ||
+ git_buf_oom(&host) ||
+ git_buf_oom(&port) ||
+ git_buf_oom(&path) ||
+ git_buf_oom(&query) ||
+ git_buf_oom(&username) ||
+ git_buf_oom(&password))
+ return -1;
+
+ url->scheme = git_buf_detach(&scheme);
+ url->host = git_buf_detach(&host);
+ url->port = git_buf_detach(&port);
+ url->path = git_buf_detach(&path);
+ url->query = git_buf_detach(&query);
+ url->username = git_buf_detach(&username);
+ url->password = git_buf_detach(&password);
+
+ error = 0;
+
+done:
+ git_buf_dispose(&scheme);
+ git_buf_dispose(&host);
+ git_buf_dispose(&port);
+ git_buf_dispose(&path);
+ git_buf_dispose(&query);
+ git_buf_dispose(&username);
+ git_buf_dispose(&password);
+ return error;
+}
+
+int git_net_url_joinpath(
+ git_net_url *out,
+ git_net_url *one,
+ const char *two)
+{
+ git_buf path = GIT_BUF_INIT;
+ const char *query;
+ size_t one_len, two_len;
+
+ git_net_url_dispose(out);
+
+ if ((query = strchr(two, '?')) != NULL) {
+ two_len = query - two;
+
+ if (*(++query) != '\0') {
+ out->query = git__strdup(query);
+ GIT_ERROR_CHECK_ALLOC(out->query);
+ }
+ } else {
+ two_len = strlen(two);
+ }
+
+ /* Strip all trailing `/`s from the first path */
+ one_len = one->path ? strlen(one->path) : 0;
+ while (one_len && one->path[one_len - 1] == '/')
+ one_len--;
+
+ /* Strip all leading `/`s from the second path */
+ while (*two == '/') {
+ two++;
+ two_len--;
+ }
+
+ git_buf_put(&path, one->path, one_len);
+ git_buf_putc(&path, '/');
+ git_buf_put(&path, two, two_len);
+
+ if (git_buf_oom(&path))
+ return -1;
+
+ out->path = git_buf_detach(&path);
+
+ if (one->scheme) {
+ out->scheme = git__strdup(one->scheme);
+ GIT_ERROR_CHECK_ALLOC(out->scheme);
+ }
+
+ if (one->host) {
+ out->host = git__strdup(one->host);
+ GIT_ERROR_CHECK_ALLOC(out->host);
+ }
+
+ if (one->port) {
+ out->port = git__strdup(one->port);
+ GIT_ERROR_CHECK_ALLOC(out->port);
+ }
+
+ if (one->username) {
+ out->username = git__strdup(one->username);
+ GIT_ERROR_CHECK_ALLOC(out->username);
+ }
+
+ if (one->password) {
+ out->password = git__strdup(one->password);
+ GIT_ERROR_CHECK_ALLOC(out->password);
+ }
+
+ return 0;
+}
+
+/*
+ * Some servers strip the query parameters from the Location header
+ * when sending a redirect. Others leave it in place.
+ * Check for both, starting with the stripped case first,
+ * since it appears to be more common.
+ */
+static void remove_service_suffix(
+ git_net_url *url,
+ const char *service_suffix)
+{
+ const char *service_query = strchr(service_suffix, '?');
+ size_t full_suffix_len = strlen(service_suffix);
+ size_t suffix_len = service_query ?
+ (size_t)(service_query - service_suffix) : full_suffix_len;
+ size_t path_len = strlen(url->path);
+ ssize_t truncate = -1;
+
+ /*
+ * Check for a redirect without query parameters,
+ * like "/newloc/info/refs"'
+ */
+ if (suffix_len && path_len >= suffix_len) {
+ size_t suffix_offset = path_len - suffix_len;
+
+ if (git__strncmp(url->path + suffix_offset, service_suffix, suffix_len) == 0 &&
+ (!service_query || git__strcmp(url->query, service_query + 1) == 0)) {
+ truncate = suffix_offset;
+ }
+ }
+
+ /*
+ * If we haven't already found where to truncate to remove the
+ * suffix, check for a redirect with query parameters, like
+ * "/newloc/info/refs?service=git-upload-pack"
+ */
+ if (truncate < 0 && git__suffixcmp(url->path, service_suffix) == 0)
+ truncate = path_len - full_suffix_len;
+
+ /* Ensure we leave a minimum of '/' as the path */
+ if (truncate == 0)
+ truncate++;
+
+ if (truncate > 0) {
+ url->path[truncate] = '\0';
+
+ git__free(url->query);
+ url->query = NULL;
+ }
+}
+
+int git_net_url_apply_redirect(
+ git_net_url *url,
+ const char *redirect_location,
+ const char *service_suffix)
+{
+ git_net_url tmp = GIT_NET_URL_INIT;
+ int error = 0;
+
+ assert(url && redirect_location);
+
+ if (redirect_location[0] == '/') {
+ git__free(url->path);
+
+ if ((url->path = git__strdup(redirect_location)) == NULL) {
+ error = -1;
+ goto done;
+ }
+ } else {
+ git_net_url *original = url;
+
+ if ((error = git_net_url_parse(&tmp, redirect_location)) < 0)
+ goto done;
+
+ /* Validate that this is a legal redirection */
+
+ if (original->scheme &&
+ strcmp(original->scheme, tmp.scheme) != 0 &&
+ strcmp(tmp.scheme, "https") != 0) {
+ git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
+ original->scheme, tmp.scheme);
+
+ error = -1;
+ goto done;
+ }
+
+ if (original->host &&
+ git__strcasecmp(original->host, tmp.host) != 0) {
+ git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'",
+ original->host, tmp.host);
+
+ error = -1;
+ goto done;
+ }
+
+ git_net_url_swap(url, &tmp);
+ }
+
+ /* Remove the service suffix if it was given to us */
+ if (service_suffix)
+ remove_service_suffix(url, service_suffix);
+
+done:
+ git_net_url_dispose(&tmp);
+ return error;
+}
+
+bool git_net_url_valid(git_net_url *url)
+{
+ return (url->host && url->port && url->path);
+}
+
+int git_net_url_is_default_port(git_net_url *url)
+{
+ const char *default_port;
+
+ if ((default_port = default_port_for_scheme(url->scheme)) != NULL)
+ return (strcmp(url->port, default_port) == 0);
+ else
+ return false;
+}
+
+void git_net_url_swap(git_net_url *a, git_net_url *b)
+{
+ git_net_url tmp = GIT_NET_URL_INIT;
+
+ memcpy(&tmp, a, sizeof(git_net_url));
+ memcpy(a, b, sizeof(git_net_url));
+ memcpy(b, &tmp, sizeof(git_net_url));
+}
+
+int git_net_url_fmt(git_buf *buf, git_net_url *url)
+{
+ git_buf_puts(buf, url->scheme);
+ git_buf_puts(buf, "://");
+
+ if (url->username) {
+ git_buf_puts(buf, url->username);
+
+ if (url->password) {
+ git_buf_puts(buf, ":");
+ git_buf_puts(buf, url->password);
+ }
+
+ git_buf_putc(buf, '@');
+ }
+
+ git_buf_puts(buf, url->host);
+
+ if (url->port && !git_net_url_is_default_port(url)) {
+ git_buf_putc(buf, ':');
+ git_buf_puts(buf, url->port);
+ }
+
+ git_buf_puts(buf, url->path ? url->path : "/");
+
+ if (url->query) {
+ git_buf_putc(buf, '?');
+ git_buf_puts(buf, url->query);
+ }
+
+ return git_buf_oom(buf) ? -1 : 0;
+}
+
+int git_net_url_fmt_path(git_buf *buf, git_net_url *url)
+{
+ git_buf_puts(buf, url->path ? url->path : "/");
+
+ if (url->query) {
+ git_buf_putc(buf, '?');
+ git_buf_puts(buf, url->query);
+ }
+
+ return git_buf_oom(buf) ? -1 : 0;
+}
+
+void git_net_url_dispose(git_net_url *url)
+{
+ if (url->username)
+ git__memzero(url->username, strlen(url->username));
+
+ if (url->password)
+ git__memzero(url->password, strlen(url->password));
+
+ git__free(url->scheme); url->scheme = NULL;
+ git__free(url->host); url->host = NULL;
+ git__free(url->port); url->port = NULL;
+ git__free(url->path); url->path = NULL;
+ git__free(url->query); url->query = NULL;
+ git__free(url->username); url->username = NULL;
+ git__free(url->password); url->password = NULL;
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_net_h__
+#define INCLUDE_net_h__
+
+#include "common.h"
+
+typedef struct git_net_url {
+ char *scheme;
+ char *host;
+ char *port;
+ char *path;
+ char *query;
+ char *username;
+ char *password;
+} git_net_url;
+
+#define GIT_NET_URL_INIT { NULL }
+
+/** Parses a string containing a URL into a structure. */
+extern int git_net_url_parse(git_net_url *url, const char *str);
+
+/** Appends a path and/or query string to the given URL */
+extern int git_net_url_joinpath(
+ git_net_url *out,
+ git_net_url *in,
+ const char *path);
+
+/** Ensures that a URL is minimally valid (contains a host, port and path) */
+extern bool git_net_url_valid(git_net_url *url);
+
+/** Returns nonzero if the URL is on the default port. */
+extern int git_net_url_is_default_port(git_net_url *url);
+
+/* Applies a redirect to the URL with a git-aware service suffix. */
+extern int git_net_url_apply_redirect(
+ git_net_url *url,
+ const char *redirect_location,
+ const char *service_suffix);
+
+/** Swaps the contents of one URL for another. */
+extern void git_net_url_swap(git_net_url *a, git_net_url *b);
+
+/** Places the URL into the given buffer. */
+extern int git_net_url_fmt(git_buf *out, git_net_url *url);
+
+/** Place the path and query string into the given buffer. */
+extern int git_net_url_fmt_path(git_buf *buf, git_net_url *url);
+
+/** Disposes the contents of the structure. */
+extern void git_net_url_dispose(git_net_url *url);
+
+#endif
static int recv_stream(gitno_buffer *buf)
{
git_stream *io = (git_stream *) buf->cb_data;
- int ret;
+ size_t readlen = buf->len - buf->offset;
+ ssize_t ret;
- ret = git_stream_read(io, buf->data + buf->offset, buf->len - buf->offset);
+ readlen = min(readlen, INT_MAX);
+
+ ret = git_stream_read(io, buf->data + buf->offset, (int)readlen);
if (ret < 0)
return -1;
buf->offset += ret;
- return ret;
+ return (int)ret;
}
void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len)
return -1;
}
-
-static const char *default_port_http = "80";
-static const char *default_port_https = "443";
-
-const char *gitno__default_port(
- gitno_connection_data *data)
-{
- return data->use_ssl ? default_port_https : default_port_http;
-}
-
-static const char *prefix_http = "http://";
-static const char *prefix_https = "https://";
-
-int gitno_connection_data_from_url(
- gitno_connection_data *data,
- const char *url,
- const char *service_suffix)
-{
- int error = -1;
- const char *default_port = NULL, *path_search_start = NULL;
- char *original_host = NULL;
-
- /* service_suffix is optional */
- assert(data && url);
-
- /* Save these for comparison later */
- original_host = data->host;
- data->host = NULL;
- gitno_connection_data_free_ptrs(data);
-
- if (!git__prefixcmp(url, prefix_http)) {
- path_search_start = url + strlen(prefix_http);
- default_port = default_port_http;
-
- if (data->use_ssl) {
- git_error_set(GIT_ERROR_NET, "redirect from HTTPS to HTTP is not allowed");
- goto cleanup;
- }
- } else if (!git__prefixcmp(url, prefix_https)) {
- path_search_start = url + strlen(prefix_https);
- default_port = default_port_https;
- data->use_ssl = true;
- } else if (url[0] == '/')
- default_port = gitno__default_port(data);
-
- if (!default_port) {
- git_error_set(GIT_ERROR_NET, "unrecognized URL prefix");
- goto cleanup;
- }
-
- error = gitno_extract_url_parts(
- &data->host, &data->port, &data->path, &data->user, &data->pass,
- url, default_port);
-
- if (url[0] == '/') {
- /* Relative redirect; reuse original host name and port */
- path_search_start = url;
- git__free(data->host);
- data->host = original_host;
- original_host = NULL;
- }
-
- if (!error) {
- const char *path = strchr(path_search_start, '/');
- size_t pathlen = strlen(path);
- size_t suffixlen = service_suffix ? strlen(service_suffix) : 0;
-
- if (suffixlen &&
- !memcmp(path + pathlen - suffixlen, service_suffix, suffixlen)) {
- git__free(data->path);
- data->path = git__strndup(path, pathlen - suffixlen);
- } else {
- git__free(data->path);
- data->path = git__strdup(path);
- }
-
- /* Check for errors in the resulting data */
- if (original_host && url[0] != '/' && strcmp(original_host, data->host)) {
- git_error_set(GIT_ERROR_NET, "cross host redirect not allowed");
- error = -1;
- }
- }
-
-cleanup:
- if (original_host) git__free(original_host);
- return error;
-}
-
-void gitno_connection_data_free_ptrs(gitno_connection_data *d)
-{
- git__free(d->host); d->host = NULL;
- git__free(d->port); d->port = NULL;
- git__free(d->path); d->path = NULL;
- git__free(d->user); d->user = NULL;
- git__free(d->pass); d->pass = NULL;
-}
-
-int gitno_extract_url_parts(
- char **host_out,
- char **port_out,
- char **path_out,
- char **username_out,
- char **password_out,
- const char *url,
- const char *default_port)
-{
- struct http_parser_url u = {0};
- bool has_host, has_port, has_path, has_userinfo;
- git_buf host = GIT_BUF_INIT,
- port = GIT_BUF_INIT,
- path = GIT_BUF_INIT,
- username = GIT_BUF_INIT,
- password = GIT_BUF_INIT;
- int error = 0;
-
- if (http_parser_parse_url(url, strlen(url), false, &u)) {
- git_error_set(GIT_ERROR_NET, "malformed URL '%s'", url);
- error = GIT_EINVALIDSPEC;
- goto done;
- }
-
- has_host = !!(u.field_set & (1 << UF_HOST));
- has_port = !!(u.field_set & (1 << UF_PORT));
- has_path = !!(u.field_set & (1 << UF_PATH));
- has_userinfo = !!(u.field_set & (1 << UF_USERINFO));
-
- if (has_host) {
- const char *url_host = url + u.field_data[UF_HOST].off;
- size_t url_host_len = u.field_data[UF_HOST].len;
- git_buf_decode_percent(&host, url_host, url_host_len);
- }
-
- if (has_port) {
- const char *url_port = url + u.field_data[UF_PORT].off;
- size_t url_port_len = u.field_data[UF_PORT].len;
- git_buf_put(&port, url_port, url_port_len);
- } else {
- git_buf_puts(&port, default_port);
- }
-
- if (has_path && path_out) {
- const char *url_path = url + u.field_data[UF_PATH].off;
- size_t url_path_len = u.field_data[UF_PATH].len;
- git_buf_decode_percent(&path, url_path, url_path_len);
- } else if (path_out) {
- git_error_set(GIT_ERROR_NET, "invalid url, missing path");
- error = GIT_EINVALIDSPEC;
- goto done;
- }
-
- if (has_userinfo) {
- const char *url_userinfo = url + u.field_data[UF_USERINFO].off;
- size_t url_userinfo_len = u.field_data[UF_USERINFO].len;
- const char *colon = memchr(url_userinfo, ':', url_userinfo_len);
-
- if (colon) {
- const char *url_username = url_userinfo;
- size_t url_username_len = colon - url_userinfo;
- const char *url_password = colon + 1;
- size_t url_password_len = url_userinfo_len - (url_username_len + 1);
-
- git_buf_decode_percent(&username, url_username, url_username_len);
- git_buf_decode_percent(&password, url_password, url_password_len);
- } else {
- git_buf_decode_percent(&username, url_userinfo, url_userinfo_len);
- }
- }
-
- if (git_buf_oom(&host) ||
- git_buf_oom(&port) ||
- git_buf_oom(&path) ||
- git_buf_oom(&username) ||
- git_buf_oom(&password))
- return -1;
-
- *host_out = git_buf_detach(&host);
- *port_out = git_buf_detach(&port);
- if (path_out)
- *path_out = git_buf_detach(&path);
- *username_out = git_buf_detach(&username);
- *password_out = git_buf_detach(&password);
-
-done:
- git_buf_dispose(&host);
- git_buf_dispose(&port);
- git_buf_dispose(&path);
- git_buf_dispose(&username);
- git_buf_dispose(&password);
- return error;
-}
#include "posix.h"
#include "stream.h"
+#include "net.h"
#ifdef GIT_OPENSSL
# include <openssl/ssl.h>
void gitno_consume(gitno_buffer *buf, const char *ptr);
void gitno_consume_n(gitno_buffer *buf, size_t cons);
-typedef struct gitno_connection_data {
- char *host;
- char *port;
- char *path;
- char *user;
- char *pass;
- bool use_ssl;
-} gitno_connection_data;
-
-/*
- * This replaces all the pointers in `data` with freshly-allocated strings,
- * that the caller is responsible for freeing.
- * `gitno_connection_data_free_ptrs` is good for this.
- */
-
-int gitno_connection_data_from_url(
- gitno_connection_data *data,
- const char *url,
- const char *service_suffix);
-
-/* This frees all the pointers IN the struct, but not the struct itself. */
-void gitno_connection_data_free_ptrs(gitno_connection_data *data);
-
-int gitno_extract_url_parts(
- char **host,
- char **port,
- char **path,
- char **username,
- char **password,
- const char *url,
- const char *default_port);
-
-const char *gitno__default_port(gitno_connection_data *data);
-
#endif
/* TODO: should we apply filters? */
/* create note object */
- if ((error = git_blob_create_frombuffer(&oid, repo, note, strlen(note))) < 0)
+ if ((error = git_blob_create_from_buffer(&oid, repo, note, strlen(note))) < 0)
goto cleanup;
if ((error = manipulate_note_in_tree_r(
git_blob *blob)
{
git_note *note = NULL;
- git_off_t blobsize;
+ git_object_size_t blobsize;
note = git__malloc(sizeof(git_note));
GIT_ERROR_CHECK_ALLOC(note);
git_oid_cpy(note_id, &item->id);
- if (!(error = process_entry_path(item->path, annotated_id)))
- git_iterator_advance(NULL, it);
+ if ((error = process_entry_path(item->path, annotated_id)) < 0)
+ return error;
- return error;
+ if ((error = git_iterator_advance(NULL, it)) < 0 && error != GIT_ITEROVER)
+ return error;
+
+ return 0;
}
bool git_object__strict_input_validation = true;
extern int git_odb_hash(git_oid *out, const void *data, size_t len, git_object_t type);
+size_t git_object__size(git_object_t type);
typedef struct {
const char *str; /* type name string */
GIT_ERROR_CHECK_ALLOC(object);
object->cached.flags = GIT_CACHE_STORE_PARSED;
object->cached.type = type;
- git_odb_hash(&object->cached.oid, data, size, type);
+ if ((error = git_odb_hash(&object->cached.oid, data, size, type)) < 0)
+ return error;
/* Parse raw object data */
def = &git_objects_table[type];
if (type != GIT_OBJECT_ANY && type != object->cached.type) {
git_object_free(object);
git_error_set(GIT_ERROR_INVALID,
- "the requested type does not match the type in ODB");
+ "the requested type does not match the type in the ODB");
return GIT_ENOTFOUND;
}
git_buf_sanitize(out);
repo = git_object_owner(obj);
- if ((error = git_repository__cvar(&len, repo, GIT_CVAR_ABBREV)) < 0)
+ if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0)
return error;
if ((error = git_repository_odb(&odb, repo)) < 0)
return true;
}
-
#include "repository.h"
+#define GIT_OBJECT_SIZE_MAX UINT64_MAX
+
extern bool git_object__strict_input_validation;
/** Base git object for inheritance */
#include <zlib.h>
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "delta.h"
#include "filter.h"
static git_cache *odb_cache(git_odb *odb)
{
- if (odb->rc.owner != NULL) {
- git_repository *owner = odb->rc.owner;
+ git_repository *owner = GIT_REFCOUNT_OWNER(odb);
+ if (owner != NULL) {
return &owner->objects;
}
size_t *written,
char *hdr,
size_t hdr_size,
- git_off_t obj_len,
+ git_object_size_t obj_len,
git_object_t obj_type)
{
const char *type_str = git_object_type2string(obj_type);
int git_odb_hashfile(git_oid *out, const char *path, git_object_t type)
{
- git_off_t size;
- int result, fd = git_futils_open_ro(path);
- if (fd < 0)
+ uint64_t size;
+ int fd, error = 0;
+
+ if ((fd = git_futils_open_ro(path)) < 0)
return fd;
- if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
+ if ((error = git_futils_filesize(&size, fd)) < 0)
+ goto done;
+
+ if (!git__is_sizet(size)) {
git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
- p_close(fd);
- return -1;
+ error = -1;
+ goto done;
}
- result = git_odb__hashfd(out, fd, (size_t)size, type);
+ error = git_odb__hashfd(out, fd, (size_t)size, type);
+
+done:
p_close(fd);
- return result;
+ return error;
}
int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
git__free(stream);
}
-static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_off_t size, git_object_t type)
+static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_object_size_t size, git_object_t type)
{
fake_wstream *stream;
size_t blobsize;
return -1;
}
if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
- git_cache_free(&db->own_cache);
+ git_cache_dispose(&db->own_cache);
git__free(db);
return -1;
}
#else
if (p_stat(objects_dir, &st) < 0) {
if (as_alternates)
+ /* this should warn */
return 0;
git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir);
int git_odb__set_caps(git_odb *odb, int caps)
{
if (caps == GIT_ODB_CAP_FROM_OWNER) {
- git_repository *repo = odb->rc.owner;
+ git_repository *repo = GIT_REFCOUNT_OWNER(odb);
int val;
if (!repo) {
return -1;
}
- if (!git_repository__cvar(&val, repo, GIT_CVAR_FSYNCOBJECTFILES))
+ if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FSYNCOBJECTFILES))
odb->do_fsync = !!val;
}
}
git_vector_free(&db->backends);
- git_cache_free(&db->own_cache);
+ git_cache_dispose(&db->own_cache);
git__memzero(db, sizeof(*db));
git__free(db);
assert(db && id);
- if (git_oid_iszero(id))
+ if (git_oid_is_zero(id))
return 0;
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
*out = NULL;
- if (git_oid_iszero(id))
+ if (git_oid_is_zero(id))
return error_null_oid(GIT_ENOTFOUND, "cannot read object");
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
assert(out && db && id);
- if (git_oid_iszero(id))
+ if (git_oid_is_zero(id))
return error_null_oid(GIT_ENOTFOUND, "cannot read object");
*out = git_cache_get_raw(odb_cache(db), id);
size_t _unused;
int error;
- if (git_oid_iszero(id))
+ if (git_oid_is_zero(id))
return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
git_oid *oid, git_odb *db, const void *data, size_t len, git_object_t type)
{
size_t i;
- int error = GIT_ERROR;
+ int error;
git_odb_stream *stream;
assert(oid && db);
- git_odb_hash(oid, data, len, type);
+ if ((error = git_odb_hash(oid, data, len, type)) < 0)
+ return error;
- if (git_oid_iszero(oid))
+ if (git_oid_is_zero(oid))
return error_null_oid(GIT_EINVALID, "cannot write object");
if (git_odb__freshen(db, oid))
return 0;
- for (i = 0; i < db->backends.length && error < 0; ++i) {
+ for (i = 0, error = GIT_ERROR; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
return error;
}
-static int hash_header(git_hash_ctx *ctx, git_off_t size, git_object_t type)
+static int hash_header(git_hash_ctx *ctx, git_object_size_t size, git_object_t type)
{
char header[64];
size_t hdrlen;
}
int git_odb_open_wstream(
- git_odb_stream **stream, git_odb *db, git_off_t size, git_object_t type)
+ git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type)
{
size_t i, writes = 0;
int error = GIT_ERROR;
return error;
}
-int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_transfer_progress_cb progress_cb, void *progress_payload)
+int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload)
{
size_t i, writes = 0;
int error = GIT_ERROR;
return error;
}
-void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
+void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len)
{
GIT_UNUSED(backend);
return git__malloc(len);
}
+#ifndef GIT_DEPRECATE_HARD
+void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
+{
+ return git_odb_backend_data_alloc(backend, len);
+}
+#endif
+
+void git_odb_backend_data_free(git_odb_backend *backend, void *data)
+{
+ GIT_UNUSED(backend);
+ git__free(data);
+}
+
int git_odb_refresh(struct git_odb *db)
{
size_t i;
/*
* Format the object header such as it would appear in the on-disk object
*/
-int git_odb__format_object_header(size_t *out_len, char *hdr, size_t hdr_size, git_off_t obj_len, git_object_t obj_type);
+int git_odb__format_object_header(size_t *out_len, char *hdr, size_t hdr_size, git_object_size_t obj_len, git_object_t obj_type);
+
/*
* Hash an open file descriptor.
* This is a performance call when the contents of a fd need to be hashed,
* symlink, then the raw contents of the symlink will be hashed. Otherwise,
* this will fallback to `git_odb__hashfd`.
*
- * The hash type for this call is always `GIT_OBJIECT_BLOB` because
+ * The hash type for this call is always `GIT_OBJECT_BLOB` because
* symlinks may only point to blobs.
*/
int git_odb__hashlink(git_oid *out, const char *path);
#include <zlib.h>
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "odb.h"
#include "delta.h"
* (including the initial sequence in the head buffer).
*/
if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr.size, 1) ||
- (body = git__malloc(alloc_size)) == NULL) {
+ (body = git__calloc(1, alloc_size)) == NULL) {
error = -1;
goto done;
}
git_rawobj *out, const unsigned char *data, size_t len)
{
git_zstream zs = GIT_ZSTREAM_INIT;
- obj_hdr hdr;
- unsigned char inflated[MAX_HEADER_LEN];
+ obj_hdr hdr = {0};
+ unsigned char inflated[MAX_HEADER_LEN] = {0};
size_t header_len, inflated_len = sizeof(inflated);
int error;
static int read_header_loose(git_rawobj *out, git_buf *loc)
{
unsigned char obj[1024];
- int fd, obj_len, error;
+ ssize_t obj_len;
+ int fd, error;
assert(out && loc);
out->data = NULL;
- if ((error = fd = git_futils_open_ro(loc->ptr)) < 0 ||
- (error = obj_len = p_read(fd, obj, sizeof(obj))) < 0)
+ if ((error = fd = git_futils_open_ro(loc->ptr)) < 0)
+ goto done;
+
+ if ((obj_len = p_read(fd, obj, sizeof(obj))) < 0) {
+ error = (int)obj_len;
goto done;
+ }
if (!is_zlib_compressed_data(obj, (size_t)obj_len))
error = read_header_loose_packlike(out, obj, (size_t)obj_len);
return flags;
}
-static int loose_backend__writestream(git_odb_stream **stream_out, git_odb_backend *_backend, git_off_t length, git_object_t type)
+static int loose_backend__writestream(git_odb_stream **stream_out, git_odb_backend *_backend, git_object_size_t length, git_object_t type)
{
loose_backend *backend;
loose_writestream *stream = NULL;
size_t hdrlen;
int error;
- assert(_backend && length >= 0);
+ assert(_backend);
backend = (loose_backend *)_backend;
*stream_out = NULL;
size_t start_remain = stream->start_len - stream->start_read;
int total = 0, error;
+ buffer_len = min(buffer_len, INT_MAX);
+
/*
* if we read more than just the header in the initial read, play
* that back for the caller.
buffer += chunk;
stream->start_read += chunk;
- total += chunk;
+ total += (int)chunk;
buffer_len -= chunk;
}
if (buffer_len) {
- size_t chunk = min(buffer_len, INT_MAX);
+ size_t chunk = buffer_len;
if ((error = git_zstream_get_output(buffer, &chunk, &stream->zstream)) < 0)
return error;
- total += chunk;
+ total += (int)chunk;
}
- return total;
+ return (int)total;
}
static void loose_backend__readstream_free(git_odb_stream *_stream)
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
#include "git2/sys/mempack.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "odb.h"
#include "array.h"
{
struct memory_packer_db *db = (struct memory_packer_db *)_backend;
struct memobject *obj = NULL;
- size_t pos;
size_t alloc_len;
- int rval;
- pos = git_oidmap_put(db->objects, oid, &rval);
- if (rval < 0)
- return -1;
-
- if (rval == 0)
+ if (git_oidmap_exists(db->objects, oid))
return 0;
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(struct memobject), len);
obj->len = len;
obj->type = type;
- git_oidmap_set_key_at(db->objects, pos, &obj->oid);
- git_oidmap_set_value_at(db->objects, pos, obj);
+ if (git_oidmap_set(db->objects, &obj->oid, obj) < 0)
+ return -1;
if (type == GIT_OBJECT_COMMIT) {
struct memobject **store = git_array_alloc(db->commits);
static int impl__read(void **buffer_p, size_t *len_p, git_object_t *type_p, git_odb_backend *backend, const git_oid *oid)
{
struct memory_packer_db *db = (struct memory_packer_db *)backend;
- struct memobject *obj = NULL;
- size_t pos;
+ struct memobject *obj;
- pos = git_oidmap_lookup_index(db->objects, oid);
- if (!git_oidmap_valid_index(db->objects, pos))
+ if ((obj = git_oidmap_get(db->objects, oid)) == NULL)
return GIT_ENOTFOUND;
- obj = git_oidmap_value_at(db->objects, pos);
-
*len_p = obj->len;
*type_p = obj->type;
*buffer_p = git__malloc(obj->len);
static int impl__read_header(size_t *len_p, git_object_t *type_p, git_odb_backend *backend, const git_oid *oid)
{
struct memory_packer_db *db = (struct memory_packer_db *)backend;
- struct memobject *obj = NULL;
- size_t pos;
+ struct memobject *obj;
- pos = git_oidmap_lookup_index(db->objects, oid);
- if (!git_oidmap_valid_index(db->objects, pos))
+ if ((obj = git_oidmap_get(db->objects, oid)) == NULL)
return GIT_ENOTFOUND;
- obj = git_oidmap_value_at(db->objects, pos);
-
*len_p = obj->len;
*type_p = obj->type;
return 0;
if (git_packbuilder_new(&packbuilder, repo) < 0)
return -1;
+ git_packbuilder_set_threads(packbuilder, 0);
+
for (i = 0; i < db->commits.size; ++i) {
struct memobject *commit = db->commits.ptr[i];
return err;
}
-void git_mempack_reset(git_odb_backend *_backend)
+int git_mempack_reset(git_odb_backend *_backend)
{
struct memory_packer_db *db = (struct memory_packer_db *)_backend;
struct memobject *object = NULL;
git_array_clear(db->commits);
git_oidmap_clear(db->objects);
+
+ return 0;
}
static void impl__free(git_odb_backend *_backend)
db = git__calloc(1, sizeof(struct memory_packer_db));
GIT_ERROR_CHECK_ALLOC(db);
- db->objects = git_oidmap_alloc();
+ if (git_oidmap_new(&db->objects) < 0)
+ return -1;
db->parent.version = GIT_ODB_BACKEND_VERSION;
db->parent.read = &impl__read;
#include "git2/repository.h"
#include "git2/indexer.h"
#include "git2/sys/odb_backend.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "odb.h"
#include "delta.h"
-#include "sha1_lookup.h"
#include "mwindow.h"
#include "pack.h"
return 0;
}
-static int pack_backend__writepack_append(struct git_odb_writepack *_writepack, const void *data, size_t size, git_transfer_progress *stats)
+static int pack_backend__writepack_append(struct git_odb_writepack *_writepack, const void *data, size_t size, git_indexer_progress *stats)
{
struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
return git_indexer_append(writepack->indexer, data, size, stats);
}
-static int pack_backend__writepack_commit(struct git_odb_writepack *_writepack, git_transfer_progress *stats)
+static int pack_backend__writepack_commit(struct git_odb_writepack *_writepack, git_indexer_progress *stats)
{
struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
static int pack_backend__writepack(struct git_odb_writepack **out,
git_odb_backend *_backend,
git_odb *odb,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress_cb progress_cb,
void *progress_payload)
{
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
#define kfree git__free
#include "khash.h"
-__KHASH_TYPE(off, git_off_t, void *)
+__KHASH_TYPE(off, off64_t, void *)
-__KHASH_IMPL(off, static kh_inline, git_off_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal)
+__KHASH_IMPL(off, static kh_inline, off64_t, void *, 1, kh_int64_hash_func, kh_int64_hash_equal)
-git_offmap *git_offmap_alloc(void)
+
+int git_offmap_new(git_offmap **out)
{
- return kh_init(off);
+ *out = kh_init(off);
+ GIT_ERROR_CHECK_ALLOC(*out);
+
+ return 0;
}
void git_offmap_free(git_offmap *map)
kh_clear(off, map);
}
-size_t git_offmap_num_entries(git_offmap *map)
+size_t git_offmap_size(git_offmap *map)
{
return kh_size(map);
}
-size_t git_offmap_lookup_index(git_offmap *map, const git_off_t key)
-{
- return kh_get(off, map, key);
-}
-
-int git_offmap_valid_index(git_offmap *map, size_t idx)
+void *git_offmap_get(git_offmap *map, const off64_t key)
{
- return idx != kh_end(map);
-}
-
-int git_offmap_exists(git_offmap *map, const git_off_t key)
-{
- return kh_get(off, map, key) != kh_end(map);
+ size_t idx = kh_get(off, map, key);
+ if (idx == kh_end(map) || !kh_exist(map, idx))
+ return NULL;
+ return kh_val(map, idx);
}
-int git_offmap_has_data(git_offmap *map, size_t idx)
+int git_offmap_set(git_offmap *map, const off64_t key, void *value)
{
- return kh_exist(map, idx);
-}
+ size_t idx;
+ int rval;
-git_off_t git_offmap_key_at(git_offmap *map, size_t idx)
-{
- return kh_key(map, idx);
-}
+ idx = kh_put(off, map, key, &rval);
+ if (rval < 0)
+ return -1;
-void *git_offmap_value_at(git_offmap *map, size_t idx)
-{
- return kh_val(map, idx);
-}
+ if (rval == 0)
+ kh_key(map, idx) = key;
-void git_offmap_set_value_at(git_offmap *map, size_t idx, void *value)
-{
kh_val(map, idx) = value;
+
+ return 0;
}
-void git_offmap_delete_at(git_offmap *map, size_t idx)
+int git_offmap_delete(git_offmap *map, const off64_t key)
{
+ khiter_t idx = kh_get(off, map, key);
+ if (idx == kh_end(map))
+ return GIT_ENOTFOUND;
kh_del(off, map, idx);
+ return 0;
}
-int git_offmap_put(git_offmap *map, const git_off_t key, int *err)
+int git_offmap_exists(git_offmap *map, const off64_t key)
{
- return kh_put(off, map, key, err);
+ return kh_get(off, map, key) != kh_end(map);
}
-void git_offmap_insert(git_offmap *map, const git_off_t key, void *value, int *rval)
+int git_offmap_iterate(void **value, git_offmap *map, size_t *iter, off64_t *key)
{
- khiter_t idx = kh_put(off, map, key, rval);
+ size_t i = *iter;
- if ((*rval) >= 0) {
- if ((*rval) == 0)
- kh_key(map, idx) = key;
- kh_val(map, idx) = value;
- }
-}
+ while (i < map->n_buckets && !kh_exist(map, i))
+ i++;
-void git_offmap_delete(git_offmap *map, const git_off_t key)
-{
- khiter_t idx = git_offmap_lookup_index(map, key);
- if (git_offmap_valid_index(map, idx))
- git_offmap_delete_at(map, idx);
-}
+ if (i >= map->n_buckets)
+ return GIT_ITEROVER;
-size_t git_offmap_begin(git_offmap *map)
-{
- GIT_UNUSED(map);
- return 0;
-}
+ if (key)
+ *key = kh_key(map, i);
+ if (value)
+ *value = kh_value(map, i);
+ *iter = ++i;
-size_t git_offmap_end(git_offmap *map)
-{
- return map->n_buckets;
+ return 0;
}
#include "git2/types.h"
+/** A map with `off64_t`s as key. */
typedef struct kh_off_s git_offmap;
-git_offmap *git_offmap_alloc(void);
+/**
+ * Allocate a new `off64_t` map.
+ *
+ * @param out Pointer to the map that shall be allocated.
+ * @return 0 on success, an error code if allocation has failed.
+ */
+int git_offmap_new(git_offmap **out);
+
+/**
+ * Free memory associated with the map.
+ *
+ * Note that this function will _not_ free values added to this
+ * map.
+ *
+ * @param map Pointer to the map that is to be free'd. May be
+ * `NULL`.
+ */
void git_offmap_free(git_offmap *map);
+
+/**
+ * Clear all entries from the map.
+ *
+ * This function will remove all entries from the associated map.
+ * Memory associated with it will not be released, though.
+ *
+ * @param map Pointer to the map that shall be cleared. May be
+ * `NULL`.
+ */
void git_offmap_clear(git_offmap *map);
-size_t git_offmap_num_entries(git_offmap *map);
+/**
+ * Return the number of elements in the map.
+ *
+ * @parameter map map containing the elements
+ * @return number of elements in the map
+ */
+size_t git_offmap_size(git_offmap *map);
-size_t git_offmap_lookup_index(git_offmap *map, const git_off_t key);
-int git_offmap_valid_index(git_offmap *map, size_t idx);
+/**
+ * Return value associated with the given key.
+ *
+ * @param map map to search key in
+ * @param key key to search for
+ * @return value associated with the given key or NULL if the key was not found
+ */
+void *git_offmap_get(git_offmap *map, const off64_t key);
-int git_offmap_exists(git_offmap *map, const git_off_t key);
-int git_offmap_has_data(git_offmap *map, size_t idx);
+/**
+ * Set the entry for key to value.
+ *
+ * If the map has no corresponding entry for the given key, a new
+ * entry will be created with the given value. If an entry exists
+ * already, its value will be updated to match the given value.
+ *
+ * @param map map to create new entry in
+ * @param key key to set
+ * @param value value to associate the key with; may be NULL
+ * @return zero if the key was successfully set, a negative error
+ * code otherwise
+ */
+int git_offmap_set(git_offmap *map, const off64_t key, void *value);
-git_off_t git_offmap_key_at(git_offmap *map, size_t idx);
-void *git_offmap_value_at(git_offmap *map, size_t idx);
-void git_offmap_set_value_at(git_offmap *map, size_t idx, void *value);
-void git_offmap_delete_at(git_offmap *map, size_t idx);
+/**
+ * Delete an entry from the map.
+ *
+ * Delete the given key and its value from the map. If no such
+ * key exists, this will do nothing.
+ *
+ * @param map map to delete key in
+ * @param key key to delete
+ * @return `0` if the key has been deleted, GIT_ENOTFOUND if no
+ * such key was found, a negative code in case of an
+ * error
+ */
+int git_offmap_delete(git_offmap *map, const off64_t key);
-int git_offmap_put(git_offmap *map, const git_off_t key, int *err);
-void git_offmap_insert(git_offmap *map, const git_off_t key, void *value, int *rval);
-void git_offmap_delete(git_offmap *map, const git_off_t key);
+/**
+ * Check whether a key exists in the given map.
+ *
+ * @param map map to query for the key
+ * @param key key to search for
+ * @return 0 if the key has not been found, 1 otherwise
+ */
+int git_offmap_exists(git_offmap *map, const off64_t key);
-size_t git_offmap_begin(git_offmap *map);
-size_t git_offmap_end(git_offmap *map);
+/**
+ * Iterate over entries of the map.
+ *
+ * This functions allows to iterate over all key-value entries of
+ * the map. The current position is stored in the `iter` variable
+ * and should be initialized to `0` before the first call to this
+ * function.
+ *
+ * @param map map to iterate over
+ * @param value pointer to the variable where to store the current
+ * value. May be NULL.
+ * @param iter iterator storing the current position. Initialize
+ * with zero previous to the first call.
+ * @param key pointer to the variable where to store the current
+ * key. May be NULL.
+ * @return `0` if the next entry was correctly retrieved.
+ * GIT_ITEROVER if no entries are left. A negative error
+ * code otherwise.
+ */
+int git_offmap_iterate(void **value, git_offmap *map, size_t *iter, off64_t *key);
-#define git_offmap_foreach(h, kvar, vvar, code) { size_t __i; \
- for (__i = git_offmap_begin(h); __i != git_offmap_end(h); ++__i) { \
- if (!git_offmap_has_data(h,__i)) continue; \
- (kvar) = git_offmap_key_at(h,__i); \
- (vvar) = git_offmap_value_at(h,__i); \
+#define git_offmap_foreach(h, kvar, vvar, code) { size_t __i = 0; \
+ while (git_offmap_iterate((void **) &(vvar), h, &__i, &(kvar)) == 0) { \
code; \
} }
-#define git_offmap_foreach_value(h, vvar, code) { size_t __i; \
- for (__i = git_offmap_begin(h); __i != git_offmap_end(h); ++__i) { \
- if (!git_offmap_has_data(h,__i)) continue; \
- (vvar) = git_offmap_value_at(h,__i); \
+#define git_offmap_foreach_value(h, vvar, code) { size_t __i = 0; \
+ while (git_offmap_iterate((void **) &(vvar), h, &__i, NULL) == 0) { \
code; \
} }
return str;
}
-void git_oid_nfmt(char *str, size_t n, const git_oid *oid)
+int git_oid_nfmt(char *str, size_t n, const git_oid *oid)
{
size_t i, max_i;
if (!oid) {
memset(str, 0, n);
- return;
+ return 0;
}
if (n > GIT_OID_HEXSZ) {
memset(&str[GIT_OID_HEXSZ], 0, n - GIT_OID_HEXSZ);
if (n & 1)
*str++ = to_hex[oid->id[i] >> 4];
+
+ return 0;
}
-void git_oid_fmt(char *str, const git_oid *oid)
+int git_oid_fmt(char *str, const git_oid *oid)
{
- git_oid_nfmt(str, GIT_OID_HEXSZ, oid);
+ return git_oid_nfmt(str, GIT_OID_HEXSZ, oid);
}
-void git_oid_pathfmt(char *str, const git_oid *oid)
+int git_oid_pathfmt(char *str, const git_oid *oid)
{
size_t i;
*str++ = '/';
for (i = 1; i < sizeof(oid->id); i++)
str = fmt_one(str, oid->id[i]);
+
+ return 0;
}
char *git_oid_tostr_s(const git_oid *oid)
git_buf_putc(buf, '\n');
}
-void git_oid_fromraw(git_oid *out, const unsigned char *raw)
+int git_oid_fromraw(git_oid *out, const unsigned char *raw)
{
memcpy(out->id, raw, sizeof(out->id));
+ return 0;
}
-void git_oid_cpy(git_oid *out, const git_oid *src)
+int git_oid_cpy(git_oid *out, const git_oid *src)
{
memcpy(out->id, src->id, sizeof(out->id));
+ return 0;
}
int git_oid_cmp(const git_oid *a, const git_oid *b)
return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1;
}
-int git_oid_iszero(const git_oid *oid_a)
+int git_oid_is_zero(const git_oid *oid_a)
{
const unsigned char *a = oid_a->id;
unsigned int i;
return 1;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_oid_iszero(const git_oid *oid_a)
+{
+ return git_oid_is_zero(oid_a);
+}
+#endif
+
typedef short node_index;
typedef union {
__KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal)
-git_oidmap *git_oidmap_alloc()
+int git_oidmap_new(git_oidmap **out)
{
- return kh_init(oid);
+ *out = kh_init(oid);
+ GIT_ERROR_CHECK_ALLOC(*out);
+
+ return 0;
}
void git_oidmap_free(git_oidmap *map)
return kh_size(map);
}
-size_t git_oidmap_lookup_index(git_oidmap *map, const git_oid *key)
-{
- return kh_get(oid, map, key);
-}
-
-int git_oidmap_valid_index(git_oidmap *map, size_t idx)
-{
- return idx != kh_end(map);
-}
-
-int git_oidmap_exists(git_oidmap *map, const git_oid *key)
+void *git_oidmap_get(git_oidmap *map, const git_oid *key)
{
- return kh_get(oid, map, key) != kh_end(map);
-}
-
-int git_oidmap_has_data(git_oidmap *map, size_t idx)
-{
- return kh_exist(map, idx);
+ size_t idx = kh_get(oid, map, key);
+ if (idx == kh_end(map) || !kh_exist(map, idx))
+ return NULL;
+ return kh_val(map, idx);
}
-const git_oid *git_oidmap_key(git_oidmap *map, size_t idx)
+int git_oidmap_set(git_oidmap *map, const git_oid *key, void *value)
{
- return kh_key(map, idx);
-}
+ size_t idx;
+ int rval;
-void git_oidmap_set_key_at(git_oidmap *map, size_t idx, git_oid *key)
-{
- kh_key(map, idx) = key;
-}
+ idx = kh_put(oid, map, key, &rval);
+ if (rval < 0)
+ return -1;
-void *git_oidmap_value_at(git_oidmap *map, size_t idx)
-{
- return kh_val(map, idx);
-}
+ if (rval == 0)
+ kh_key(map, idx) = key;
-void git_oidmap_set_value_at(git_oidmap *map, size_t idx, void *value)
-{
kh_val(map, idx) = value;
+
+ return 0;
}
-void git_oidmap_delete_at(git_oidmap *map, size_t idx)
+int git_oidmap_delete(git_oidmap *map, const git_oid *key)
{
+ khiter_t idx = kh_get(oid, map, key);
+ if (idx == kh_end(map))
+ return GIT_ENOTFOUND;
kh_del(oid, map, idx);
+ return 0;
}
-int git_oidmap_put(git_oidmap *map, const git_oid *key, int *err)
+int git_oidmap_exists(git_oidmap *map, const git_oid *key)
{
- return kh_put(oid, map, key, err);
+ return kh_get(oid, map, key) != kh_end(map);
}
-void git_oidmap_insert(git_oidmap *map, const git_oid *key, void *value, int *rval)
+int git_oidmap_iterate(void **value, git_oidmap *map, size_t *iter, const git_oid **key)
{
- khiter_t idx = kh_put(oid, map, key, rval);
+ size_t i = *iter;
- if ((*rval) >= 0) {
- if ((*rval) == 0)
- kh_key(map, idx) = key;
- kh_val(map, idx) = value;
- }
-}
+ while (i < map->n_buckets && !kh_exist(map, i))
+ i++;
-void git_oidmap_delete(git_oidmap *map, const git_oid *key)
-{
- khiter_t idx = git_oidmap_lookup_index(map, key);
- if (git_oidmap_valid_index(map, idx))
- git_oidmap_delete_at(map, idx);
-}
+ if (i >= map->n_buckets)
+ return GIT_ITEROVER;
-size_t git_oidmap_begin(git_oidmap *map)
-{
- GIT_UNUSED(map);
- return 0;
-}
+ if (key)
+ *key = kh_key(map, i);
+ if (value)
+ *value = kh_value(map, i);
+ *iter = ++i;
-size_t git_oidmap_end(git_oidmap *map)
-{
- return map->n_buckets;
+ return 0;
}
#include "git2/oid.h"
+/** A map with `git_oid`s as key. */
typedef struct kh_oid_s git_oidmap;
-git_oidmap *git_oidmap_alloc(void);
+/**
+ * Allocate a new OID map.
+ *
+ * @param out Pointer to the map that shall be allocated.
+ * @return 0 on success, an error code if allocation has failed.
+ */
+int git_oidmap_new(git_oidmap **out);
+
+/**
+ * Free memory associated with the map.
+ *
+ * Note that this function will _not_ free values added to this
+ * map.
+ *
+ * @param map Pointer to the map that is to be free'd. May be
+ * `NULL`.
+ */
void git_oidmap_free(git_oidmap *map);
+
+/**
+ * Clear all entries from the map.
+ *
+ * This function will remove all entries from the associated map.
+ * Memory associated with it will not be released, though.
+ *
+ * @param map Pointer to the map that shall be cleared. May be
+ * `NULL`.
+ */
void git_oidmap_clear(git_oidmap *map);
+/**
+ * Return the number of elements in the map.
+ *
+ * @parameter map map containing the elements
+ * @return number of elements in the map
+ */
size_t git_oidmap_size(git_oidmap *map);
-size_t git_oidmap_lookup_index(git_oidmap *map, const git_oid *key);
-int git_oidmap_valid_index(git_oidmap *map, size_t idx);
+/**
+ * Return value associated with the given key.
+ *
+ * @param map map to search key in
+ * @param key key to search for
+ * @return value associated with the given key or NULL if the key was not found
+ */
+void *git_oidmap_get(git_oidmap *map, const git_oid *key);
-int git_oidmap_exists(git_oidmap *map, const git_oid *key);
-int git_oidmap_has_data(git_oidmap *map, size_t idx);
+/**
+ * Set the entry for key to value.
+ *
+ * If the map has no corresponding entry for the given key, a new
+ * entry will be created with the given value. If an entry exists
+ * already, its value will be updated to match the given value.
+ *
+ * @param map map to create new entry in
+ * @param key key to set
+ * @param value value to associate the key with; may be NULL
+ * @return zero if the key was successfully set, a negative error
+ * code otherwise
+ */
+int git_oidmap_set(git_oidmap *map, const git_oid *key, void *value);
-const git_oid *git_oidmap_key(git_oidmap *map, size_t idx);
-void git_oidmap_set_key_at(git_oidmap *map, size_t idx, git_oid *key);
-void *git_oidmap_value_at(git_oidmap *map, size_t idx);
-void git_oidmap_set_value_at(git_oidmap *map, size_t idx, void *value);
-void git_oidmap_delete_at(git_oidmap *map, size_t idx);
+/**
+ * Delete an entry from the map.
+ *
+ * Delete the given key and its value from the map. If no such
+ * key exists, this will do nothing.
+ *
+ * @param map map to delete key in
+ * @param key key to delete
+ * @return `0` if the key has been deleted, GIT_ENOTFOUND if no
+ * such key was found, a negative code in case of an
+ * error
+ */
+int git_oidmap_delete(git_oidmap *map, const git_oid *key);
-int git_oidmap_put(git_oidmap *map, const git_oid *key, int *err);
-void git_oidmap_insert(git_oidmap *map, const git_oid *key, void *value, int *rval);
-void git_oidmap_delete(git_oidmap *map, const git_oid *key);
+/**
+ * Check whether a key exists in the given map.
+ *
+ * @param map map to query for the key
+ * @param key key to search for
+ * @return 0 if the key has not been found, 1 otherwise
+ */
+int git_oidmap_exists(git_oidmap *map, const git_oid *key);
-size_t git_oidmap_begin(git_oidmap *map);
-size_t git_oidmap_end(git_oidmap *map);
+/**
+ * Iterate over entries of the map.
+ *
+ * This functions allows to iterate over all key-value entries of
+ * the map. The current position is stored in the `iter` variable
+ * and should be initialized to `0` before the first call to this
+ * function.
+ *
+ * @param map map to iterate over
+ * @param value pointer to the variable where to store the current
+ * value. May be NULL.
+ * @param iter iterator storing the current position. Initialize
+ * with zero previous to the first call.
+ * @param key pointer to the variable where to store the current
+ * key. May be NULL.
+ * @return `0` if the next entry was correctly retrieved.
+ * GIT_ITEROVER if no entries are left. A negative error
+ * code otherwise.
+ */
+int git_oidmap_iterate(void **value, git_oidmap *map, size_t *iter, const git_oid **key);
-#define git_oidmap_foreach_value(h, vvar, code) { size_t __i; \
- for (__i = git_oidmap_begin(h); __i != git_oidmap_end(h); ++__i) { \
- if (!git_oidmap_has_data(h,__i)) continue; \
- (vvar) = git_oidmap_value_at(h,__i); \
+#define git_oidmap_foreach_value(h, vvar, code) { size_t __i = 0; \
+ while (git_oidmap_iterate((void **) &(vvar), h, &__i, NULL) == 0) { \
code; \
} }
struct pack_write_context {
git_indexer *indexer;
- git_transfer_progress *stats;
+ git_indexer_progress *stats;
};
struct walk_object {
pb = git__calloc(1, sizeof(*pb));
GIT_ERROR_CHECK_ALLOC(pb);
- pb->object_ix = git_oidmap_alloc();
- if (!pb->object_ix)
+ if (git_oidmap_new(&pb->object_ix) < 0 ||
+ git_oidmap_new(&pb->walk_objects) < 0 ||
+ git_pool_init(&pb->object_pool, sizeof(struct walk_object)) < 0)
goto on_error;
- pb->walk_objects = git_oidmap_alloc();
- if (!pb->walk_objects)
- goto on_error;
-
- git_pool_init(&pb->object_pool, sizeof(struct walk_object));
-
pb->repo = repo;
pb->nr_threads = 1; /* do not spawn any thread by default */
return pb->nr_threads;
}
-static void rehash(git_packbuilder *pb)
+static int rehash(git_packbuilder *pb)
{
git_pobject *po;
- size_t pos, i;
- int ret;
+ size_t i;
git_oidmap_clear(pb->object_ix);
+
for (i = 0, po = pb->object_list; i < pb->nr_objects; i++, po++) {
- pos = git_oidmap_put(pb->object_ix, &po->id, &ret);
- git_oidmap_set_value_at(pb->object_ix, pos, po);
+ if (git_oidmap_set(pb->object_ix, &po->id, po) < 0)
+ return -1;
}
+
+ return 0;
}
int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
const char *name)
{
git_pobject *po;
- size_t newsize, pos;
+ size_t newsize;
int ret;
assert(pb && oid);
if (pb->nr_objects >= pb->nr_alloc) {
GIT_ERROR_CHECK_ALLOC_ADD(&newsize, pb->nr_alloc, 1024);
- GIT_ERROR_CHECK_ALLOC_MULTIPLY(&newsize, newsize, 3 / 2);
+ GIT_ERROR_CHECK_ALLOC_MULTIPLY(&newsize, newsize / 2, 3);
if (!git__is_uint32(newsize)) {
git_error_set(GIT_ERROR_NOMEMORY, "packfile too large to fit in memory.");
pb->object_list = git__reallocarray(pb->object_list,
pb->nr_alloc, sizeof(*po));
GIT_ERROR_CHECK_ALLOC(pb->object_list);
- rehash(pb);
+
+ if (rehash(pb) < 0)
+ return -1;
}
po = pb->object_list + pb->nr_objects;
git_oid_cpy(&po->id, oid);
po->hash = name_hash(name);
- pos = git_oidmap_put(pb->object_ix, &po->id, &ret);
- if (ret < 0) {
+ if (git_oidmap_set(pb->object_ix, &po->id, po) < 0) {
git_error_set_oom();
- return ret;
+ return -1;
}
- assert(ret != 0);
- git_oidmap_set_value_at(pb->object_ix, pos, po);
pb->done = false;
GIT_ERROR_CHECK_ALLOC(zbuf);
git_zstream_reset(&pb->zstream);
- git_zstream_set_input(&pb->zstream, data, data_len);
+
+ if ((error = git_zstream_set_input(&pb->zstream, data, data_len)) < 0)
+ goto done;
while (!git_zstream_done(&pb->zstream)) {
if ((error = git_zstream_get_output(zbuf, &zbuf_len, &pb->zstream)) < 0 ||
{
git_packbuilder *pb = data;
git_pobject *po;
- size_t pos;
GIT_UNUSED(name);
- pos = git_oidmap_lookup_index(pb->object_ix, oid);
- if (!git_oidmap_valid_index(pb->object_ix, pos))
+ if ((po = git_oidmap_get(pb->object_ix, oid)) == NULL)
return 0;
- po = git_oidmap_value_at(pb->object_ix, pos);
po->tagged = 1;
/* TODO: peel objects */
git_packbuilder *pb,
const char *path,
unsigned int mode,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress_cb progress_cb,
void *progress_cb_payload)
{
+ int error = -1;
+ git_buf object_path = GIT_BUF_INIT;
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
- git_indexer *indexer;
- git_transfer_progress stats;
+ git_indexer *indexer = NULL;
+ git_indexer_progress stats;
struct pack_write_context ctx;
int t;
PREPARE_PACK;
+ if (path == NULL) {
+ if ((error = git_repository_item_path(&object_path, pb->repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0)
+ goto cleanup;
+ if ((error = git_buf_joinpath(&object_path, git_buf_cstr(&object_path), "pack")) < 0)
+ goto cleanup;
+ path = git_buf_cstr(&object_path);
+ }
+
opts.progress_cb = progress_cb;
opts.progress_cb_payload = progress_cb_payload;
- if (git_indexer_new(
- &indexer, path, mode, pb->odb, &opts) < 0)
- return -1;
+ if ((error = git_indexer_new(&indexer, path, mode, pb->odb, &opts)) < 0)
+ goto cleanup;
- if (!git_repository__cvar(&t, pb->repo, GIT_CVAR_FSYNCOBJECTFILES) && t)
+ if (!git_repository__configmap_lookup(&t, pb->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t)
git_indexer__set_fsync(indexer, 1);
ctx.indexer = indexer;
ctx.stats = &stats;
- if (git_packbuilder_foreach(pb, write_cb, &ctx) < 0 ||
- git_indexer_commit(indexer, &stats) < 0) {
- git_indexer_free(indexer);
- return -1;
- }
+ if ((error = git_packbuilder_foreach(pb, write_cb, &ctx)) < 0)
+ goto cleanup;
+
+ if ((error = git_indexer_commit(indexer, &stats)) < 0)
+ goto cleanup;
git_oid_cpy(&pb->pack_oid, git_indexer_hash(indexer));
+cleanup:
git_indexer_free(indexer);
- return 0;
+ git_buf_dispose(&object_path);
+ return error;
}
#undef PREPARE_PACK
static int retrieve_object(struct walk_object **out, git_packbuilder *pb, const git_oid *id)
{
- int error;
- size_t pos;
struct walk_object *obj;
+ int error;
- pos = git_oidmap_lookup_index(pb->walk_objects, id);
- if (git_oidmap_valid_index(pb->walk_objects, pos)) {
- obj = git_oidmap_value_at(pb->walk_objects, pos);
- } else {
+ if ((obj = git_oidmap_get(pb->walk_objects, id)) == NULL) {
if ((error = lookup_walk_object(&obj, pb, id)) < 0)
return error;
- git_oidmap_insert(pb->walk_objects, &obj->id, obj, &error);
+ if ((error = git_oidmap_set(pb->walk_objects, &obj->id, obj)) < 0)
+ return error;
}
*out = obj;
return 0;
}
-int insert_tree(git_packbuilder *pb, git_tree *tree)
+static int pack_objects_insert_tree(git_packbuilder *pb, git_tree *tree)
{
size_t i;
int error;
if ((error = git_tree_lookup(&subtree, pb->repo, entry_id)) < 0)
return error;
- error = insert_tree(pb, subtree);
+ error = pack_objects_insert_tree(pb, subtree);
git_tree_free(subtree);
if (error < 0)
return error;
}
-int insert_commit(git_packbuilder *pb, struct walk_object *obj)
+static int pack_objects_insert_commit(git_packbuilder *pb, struct walk_object *obj)
{
int error;
git_commit *commit = NULL;
if ((error = git_tree_lookup(&tree, pb->repo, git_commit_tree_id(commit))) < 0)
goto cleanup;
- if ((error = insert_tree(pb, tree)) < 0)
+ if ((error = pack_objects_insert_tree(pb, tree)) < 0)
goto cleanup;
cleanup:
if (obj->seen || obj->uninteresting)
continue;
- if ((error = insert_commit(pb, obj)) < 0)
+ if ((error = pack_objects_insert_commit(pb, obj)) < 0)
return error;
}
typedef struct git_pobject {
git_oid id;
git_object_t type;
- git_off_t offset;
+ off64_t offset;
size_t size;
#include "pack.h"
-#include "odb.h"
#include "delta.h"
-#include "sha1_lookup.h"
+#include "futils.h"
#include "mwindow.h"
-#include "fileops.h"
+#include "odb.h"
#include "oid.h"
-#include <zlib.h>
+/* Option to bypass checking existence of '.keep' files */
+bool git_disable_pack_keep_file_checks = false;
static int packfile_open(struct git_pack_file *p);
-static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
+static off64_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
static int packfile_unpack_compressed(
git_rawobj *obj,
struct git_pack_file *p,
git_mwindow **w_curs,
- git_off_t *curpos,
+ off64_t *curpos,
size_t size,
git_object_t type);
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/
static int pack_entry_find_offset(
- git_off_t *offset_out,
+ off64_t *offset_out,
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
static int cache_init(git_pack_cache *cache)
{
- cache->entries = git_offmap_alloc();
- GIT_ERROR_CHECK_ALLOC(cache->entries);
+ if (git_offmap_new(&cache->entries) < 0)
+ return -1;
cache->memory_limit = GIT_PACK_CACHE_MEMORY_LIMIT;
return 0;
}
-static git_pack_cache_entry *cache_get(git_pack_cache *cache, git_off_t offset)
+static git_pack_cache_entry *cache_get(git_pack_cache *cache, off64_t offset)
{
- git_pack_cache_entry *entry = NULL;
- size_t k;
+ git_pack_cache_entry *entry;
if (git_mutex_lock(&cache->lock) < 0)
return NULL;
- k = git_offmap_lookup_index(cache->entries, offset);
- if (git_offmap_valid_index(cache->entries, k)) { /* found it */
- entry = git_offmap_value_at(cache->entries, k);
+ if ((entry = git_offmap_get(cache->entries, offset)) != NULL) {
git_atomic_inc(&entry->refcount);
entry->last_usage = cache->use_ctr++;
}
/* Run with the cache lock held */
static void free_lowest_entry(git_pack_cache *cache)
{
- git_off_t offset;
+ off64_t offset;
git_pack_cache_entry *entry;
git_offmap_foreach(cache->entries, offset, entry, {
git_pack_cache_entry **cached_out,
git_pack_cache *cache,
git_rawobj *base,
- git_off_t offset)
+ off64_t offset)
{
git_pack_cache_entry *entry;
- int error, exists = 0;
- size_t k;
+ int exists;
if (base->len > GIT_PACK_CACHE_SIZE_LIMIT)
return -1;
while (cache->memory_used + base->len > cache->memory_limit)
free_lowest_entry(cache);
- k = git_offmap_put(cache->entries, offset, &error);
- assert(error != 0);
- git_offmap_set_value_at(cache->entries, k, entry);
+ git_offmap_set(cache->entries, offset, entry);
cache->memory_used += entry->raw.len;
*cached_out = entry;
static unsigned char *pack_window_open(
struct git_pack_file *p,
git_mwindow **w_cursor,
- git_off_t offset,
+ off64_t offset,
unsigned int *left)
{
if (p->mwf.fd == -1 && packfile_open(p) < 0)
git_object_t *type_p,
git_mwindow_file *mwf,
git_mwindow **w_curs,
- git_off_t *curpos)
+ off64_t *curpos)
{
unsigned char *base;
unsigned int left;
size_t *size_p,
git_object_t *type_p,
struct git_pack_file *p,
- git_off_t offset)
+ off64_t offset)
{
git_mwindow *w_curs = NULL;
- git_off_t curpos = offset;
+ off64_t curpos = offset;
size_t size;
git_object_t type;
- git_off_t base_offset;
+ off64_t base_offset;
int error;
error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
size_t base_size;
git_packfile_stream stream;
- base_offset = get_delta_base(p, &w_curs, &curpos, type, offset);
+ error = get_delta_base(&base_offset, p, &w_curs, &curpos, type, offset);
git_mwindow_close(&w_curs);
+
+ if (error < 0)
+ return error;
+
if ((error = git_packfile_stream_open(&stream, p, curpos)) < 0)
return error;
error = git_delta_read_header_fromstream(&base_size, size_p, &stream);
return error;
if (type != GIT_OBJECT_OFS_DELTA && type != GIT_OBJECT_REF_DELTA)
break;
- base_offset = get_delta_base(p, &w_curs, &curpos, type, base_offset);
+
+ error = get_delta_base(&base_offset, p, &w_curs, &curpos, type, base_offset);
git_mwindow_close(&w_curs);
+
+ if (error < 0)
+ return error;
}
*type_p = type;
* cache, we stop calculating there.
*/
static int pack_dependency_chain(git_dependency_chain *chain_out,
- git_pack_cache_entry **cached_out, git_off_t *cached_off,
+ git_pack_cache_entry **cached_out, off64_t *cached_off,
struct pack_chain_elem *small_stack, size_t *stack_sz,
- struct git_pack_file *p, git_off_t obj_offset)
+ struct git_pack_file *p, off64_t obj_offset)
{
git_dependency_chain chain = GIT_ARRAY_INIT;
git_mwindow *w_curs = NULL;
- git_off_t curpos = obj_offset, base_offset;
+ off64_t curpos = obj_offset, base_offset;
int error = 0, use_heap = 0;
size_t size, elem_pos;
git_object_t type;
if (type != GIT_OBJECT_OFS_DELTA && type != GIT_OBJECT_REF_DELTA)
break;
- base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
+ error = get_delta_base(&base_offset, p, &w_curs, &curpos, type, obj_offset);
git_mwindow_close(&w_curs);
- if (base_offset == 0) {
- error = packfile_error("delta offset is zero");
- goto on_error;
- }
- if (base_offset < 0) { /* must actually be an error code */
- error = (int)base_offset;
+ if (error < 0)
goto on_error;
- }
/* we need to pass the pos *after* the delta-base bit */
elem->offset = curpos;
int git_packfile_unpack(
git_rawobj *obj,
struct git_pack_file *p,
- git_off_t *obj_offset)
+ off64_t *obj_offset)
{
git_mwindow *w_curs = NULL;
- git_off_t curpos = *obj_offset;
+ off64_t curpos = *obj_offset;
int error, free_base = 0;
git_dependency_chain chain = GIT_ARRAY_INIT;
struct pack_chain_elem *elem = NULL, *stack;
return error;
}
-static void *use_git_alloc(void *opaq, unsigned int count, unsigned int size)
+int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, off64_t curpos)
{
- GIT_UNUSED(opaq);
- return git__calloc(count, size);
-}
-
-static void use_git_free(void *opaq, void *ptr)
-{
- GIT_UNUSED(opaq);
- git__free(ptr);
-}
-
-int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos)
-{
- int st;
-
memset(obj, 0, sizeof(git_packfile_stream));
obj->curpos = curpos;
obj->p = p;
- obj->zstream.zalloc = use_git_alloc;
- obj->zstream.zfree = use_git_free;
- obj->zstream.next_in = Z_NULL;
- obj->zstream.next_out = Z_NULL;
- st = inflateInit(&obj->zstream);
- if (st != Z_OK) {
+
+ if (git_zstream_init(&obj->zstream, GIT_ZSTREAM_INFLATE) < 0) {
git_error_set(GIT_ERROR_ZLIB, "failed to init packfile stream");
return -1;
}
ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len)
{
+ unsigned int window_len;
unsigned char *in;
- size_t written;
- int st;
+ int error;
if (obj->done)
return 0;
- in = pack_window_open(obj->p, &obj->mw, obj->curpos, &obj->zstream.avail_in);
- if (in == NULL)
+ if ((in = pack_window_open(obj->p, &obj->mw, obj->curpos, &window_len)) == NULL)
return GIT_EBUFS;
- obj->zstream.next_out = buffer;
- obj->zstream.avail_out = (unsigned int)len;
- obj->zstream.next_in = in;
-
- st = inflate(&obj->zstream, Z_SYNC_FLUSH);
- git_mwindow_close(&obj->mw);
-
- obj->curpos += obj->zstream.next_in - in;
- written = len - obj->zstream.avail_out;
-
- if (st != Z_OK && st != Z_STREAM_END) {
+ if ((error = git_zstream_set_input(&obj->zstream, in, window_len)) < 0 ||
+ (error = git_zstream_get_output_chunk(buffer, &len, &obj->zstream)) < 0) {
+ git_mwindow_close(&obj->mw);
git_error_set(GIT_ERROR_ZLIB, "error reading from the zlib stream");
return -1;
}
- if (st == Z_STREAM_END)
- obj->done = 1;
+ git_mwindow_close(&obj->mw);
+
+ obj->curpos += window_len - obj->zstream.in_len;
+ if (git_zstream_eos(&obj->zstream))
+ obj->done = 1;
/* If we didn't write anything out but we're not done, we need more data */
- if (!written && st != Z_STREAM_END)
+ if (!len && !git_zstream_eos(&obj->zstream))
return GIT_EBUFS;
- return written;
+ return len;
}
void git_packfile_stream_dispose(git_packfile_stream *obj)
{
- inflateEnd(&obj->zstream);
+ git_zstream_free(&obj->zstream);
}
static int packfile_unpack_compressed(
git_rawobj *obj,
struct git_pack_file *p,
- git_mwindow **w_curs,
- git_off_t *curpos,
+ git_mwindow **mwindow,
+ off64_t *position,
size_t size,
git_object_t type)
{
- size_t buf_size;
- int st;
- z_stream stream;
- unsigned char *buffer, *in;
-
- GIT_ERROR_CHECK_ALLOC_ADD(&buf_size, size, 1);
- buffer = git__calloc(1, buf_size);
- GIT_ERROR_CHECK_ALLOC(buffer);
-
- memset(&stream, 0, sizeof(stream));
- stream.next_out = buffer;
- stream.avail_out = (uInt)buf_size;
- stream.zalloc = use_git_alloc;
- stream.zfree = use_git_free;
-
- st = inflateInit(&stream);
- if (st != Z_OK) {
- git__free(buffer);
- git_error_set(GIT_ERROR_ZLIB, "failed to init zlib stream on unpack");
+ git_zstream zstream = GIT_ZSTREAM_INIT;
+ size_t buffer_len, total = 0;
+ char *data = NULL;
+ int error;
- return -1;
+ GIT_ERROR_CHECK_ALLOC_ADD(&buffer_len, size, 1);
+ data = git__calloc(1, buffer_len);
+ GIT_ERROR_CHECK_ALLOC(data);
+
+ if ((error = git_zstream_init(&zstream, GIT_ZSTREAM_INFLATE)) < 0) {
+ git_error_set(GIT_ERROR_ZLIB, "failed to init zlib stream on unpack");
+ goto out;
}
do {
- in = pack_window_open(p, w_curs, *curpos, &stream.avail_in);
- stream.next_in = in;
- st = inflate(&stream, Z_FINISH);
- git_mwindow_close(w_curs);
+ size_t bytes = buffer_len - total;
+ unsigned int window_len;
+ unsigned char *in;
- if (!stream.avail_out)
- break; /* the payload is larger than it should be */
+ if ((in = pack_window_open(p, mwindow, *position, &window_len)) == NULL) {
+ error = -1;
+ goto out;
+ }
- if (st == Z_BUF_ERROR && in == NULL) {
- inflateEnd(&stream);
- git__free(buffer);
- return GIT_EBUFS;
+ if ((error = git_zstream_set_input(&zstream, in, window_len)) < 0 ||
+ (error = git_zstream_get_output_chunk(data + total, &bytes, &zstream)) < 0) {
+ git_mwindow_close(mwindow);
+ goto out;
}
- *curpos += stream.next_in - in;
- } while (st == Z_OK || st == Z_BUF_ERROR);
+ git_mwindow_close(mwindow);
- inflateEnd(&stream);
+ if (!bytes)
+ break;
+
+ *position += window_len - zstream.in_len;
+ total += bytes;
+ } while (!git_zstream_eos(&zstream));
- if ((st != Z_STREAM_END) || stream.total_out != size) {
- git__free(buffer);
+ if (total != size || !git_zstream_eos(&zstream)) {
git_error_set(GIT_ERROR_ZLIB, "error inflating zlib stream");
- return -1;
+ error = -1;
+ goto out;
}
obj->type = type;
obj->len = size;
- obj->data = buffer;
- return 0;
+ obj->data = data;
+
+out:
+ git_zstream_free(&zstream);
+ if (error)
+ git__free(data);
+
+ return error;
}
/*
* curpos is where the data starts, delta_obj_offset is the where the
* header starts
*/
-git_off_t get_delta_base(
- struct git_pack_file *p,
- git_mwindow **w_curs,
- git_off_t *curpos,
- git_object_t type,
- git_off_t delta_obj_offset)
+int get_delta_base(
+ off64_t *delta_base_out,
+ struct git_pack_file *p,
+ git_mwindow **w_curs,
+ off64_t *curpos,
+ git_object_t type,
+ off64_t delta_obj_offset)
{
unsigned int left = 0;
unsigned char *base_info;
- git_off_t base_offset;
+ off64_t base_offset;
git_oid unused;
+ assert(delta_base_out);
+
base_info = pack_window_open(p, w_curs, *curpos, &left);
/* Assumption: the only reason this would fail is because the file is too small */
if (base_info == NULL)
return GIT_EBUFS;
unsigned_base_offset += 1;
if (!unsigned_base_offset || MSB(unsigned_base_offset, 7))
- return 0; /* overflow */
+ return packfile_error("overflow");
c = base_info[used++];
unsigned_base_offset = (unsigned_base_offset << 7) + (c & 127);
}
if (unsigned_base_offset == 0 || (size_t)delta_obj_offset <= unsigned_base_offset)
- return 0; /* out of bound */
+ return packfile_error("out of bounds");
base_offset = delta_obj_offset - unsigned_base_offset;
*curpos += used;
} else if (type == GIT_OBJECT_REF_DELTA) {
/* If we have the cooperative cache, search in it first */
if (p->has_cache) {
+ struct git_pack_entry *entry;
git_oid oid;
- size_t k;
git_oid_fromraw(&oid, base_info);
- k = git_oidmap_lookup_index(p->idx_cache, &oid);
- if (git_oidmap_valid_index(p->idx_cache, k)) {
+ if ((entry = git_oidmap_get(p->idx_cache, &oid)) != NULL) {
+ if (entry->offset == 0)
+ return packfile_error("delta offset is zero");
+
*curpos += 20;
- return ((struct git_pack_entry *)git_oidmap_value_at(p->idx_cache, k))->offset;
+ *delta_base_out = entry->offset;
+ return 0;
} else {
/* If we're building an index, don't try to find the pack
* entry; we just haven't seen it yet. We'll make
return packfile_error("base entry delta is not in the same pack");
*curpos += 20;
} else
- return 0;
+ return packfile_error("unknown object type");
+
+ if (base_offset == 0)
+ return packfile_error("delta offset is zero");
- return base_offset;
+ *delta_base_out = base_offset;
+ return 0;
}
/***********************************************************
if (!p->mwf.size) {
if (!S_ISREG(st.st_mode))
goto cleanup;
- p->mwf.size = (git_off_t)st.st_size;
+ p->mwf.size = (off64_t)st.st_size;
} else if (p->mwf.size != st.st_size)
goto cleanup;
if (git__suffixcmp(path, ".idx") == 0) {
size_t root_len = path_len - strlen(".idx");
- memcpy(p->pack_name + root_len, ".keep", sizeof(".keep"));
- if (git_path_exists(p->pack_name) == true)
- p->pack_keep = 1;
+ if (!git_disable_pack_keep_file_checks) {
+ memcpy(p->pack_name + root_len, ".keep", sizeof(".keep"));
+ if (git_path_exists(p->pack_name) == true)
+ p->pack_keep = 1;
+ }
memcpy(p->pack_name + root_len, ".pack", sizeof(".pack"));
}
*
***********************************************************/
-static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
+static off64_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
{
const unsigned char *index = p->index_map.data;
const unsigned char *end = index + p->index_map.len;
return error;
}
+int git_pack__lookup_sha1(const void *oid_lookup_table, size_t stride, unsigned lo,
+ unsigned hi, const unsigned char *oid_prefix)
+{
+ const unsigned char *base = oid_lookup_table;
+
+ while (lo < hi) {
+ unsigned mi = (lo + hi) / 2;
+ int cmp = git_oid__hashcmp(base + mi * stride, oid_prefix);
+
+ if (!cmp)
+ return mi;
+
+ if (cmp > 0)
+ hi = mi;
+ else
+ lo = mi+1;
+ }
+
+ return -((int)lo)-1;
+}
+
static int pack_entry_find_offset(
- git_off_t *offset_out,
+ off64_t *offset_out,
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
const unsigned char *index;
unsigned hi, lo, stride;
int pos, found = 0;
- git_off_t offset;
+ off64_t offset;
const unsigned char *current = 0;
*offset_out = 0;
short_oid->id[0], short_oid->id[1], short_oid->id[2], lo, hi, p->num_objects);
#endif
- pos = sha1_position(index, stride, lo, hi, short_oid->id);
+ pos = git_pack__lookup_sha1(index, stride, lo, hi, short_oid->id);
if (pos >= 0) {
/* An object matching exactly the oid was found */
const git_oid *short_oid,
size_t len)
{
- git_off_t offset;
+ off64_t offset;
git_oid found_oid;
int error;
#include "common.h"
-#include <zlib.h>
-
#include "git2/oid.h"
+#include "array.h"
#include "map.h"
#include "mwindow.h"
#include "odb.h"
+#include "offmap.h"
#include "oidmap.h"
-#include "array.h"
+#include "zstream.h"
#define GIT_PACK_FILE_MODE 0444
} git_pack_cache_entry;
struct pack_chain_elem {
- git_off_t base_key;
- git_off_t offset;
+ off64_t base_key;
+ off64_t offset;
size_t size;
git_object_t type;
};
typedef git_array_t(struct pack_chain_elem) git_dependency_chain;
-#include "offmap.h"
-#include "oidmap.h"
-
#define GIT_PACK_CACHE_MEMORY_LIMIT 16 * 1024 * 1024
#define GIT_PACK_CACHE_SIZE_LIMIT 1024 * 1024 /* don't bother caching anything over 1MB */
char pack_name[GIT_FLEX_ARRAY]; /* more */
};
+/**
+ * Return the position where an OID (or a prefix) would be inserted within the
+ * OID Lookup Table of an .idx file. This performs binary search between the lo
+ * and hi indices.
+ *
+ * The stride parameter is provided because .idx files version 1 store the OIDs
+ * interleaved with the 4-byte file offsets of the objects within the .pack
+ * file (stride = 24), whereas files with version 2 store them in a contiguous
+ * flat array (stride = 20).
+ */
+int git_pack__lookup_sha1(const void *oid_lookup_table, size_t stride, unsigned lo,
+ unsigned hi, const unsigned char *oid_prefix);
+
struct git_pack_entry {
- git_off_t offset;
+ off64_t offset;
git_oid sha1;
struct git_pack_file *p;
};
typedef struct git_packfile_stream {
- git_off_t curpos;
+ off64_t curpos;
int done;
- z_stream zstream;
+ git_zstream zstream;
struct git_pack_file *p;
git_mwindow *mw;
} git_packfile_stream;
git_object_t *type_p,
git_mwindow_file *mwf,
git_mwindow **w_curs,
- git_off_t *curpos);
+ off64_t *curpos);
int git_packfile_resolve_header(
size_t *size_p,
git_object_t *type_p,
struct git_pack_file *p,
- git_off_t offset);
+ off64_t offset);
-int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, git_off_t *obj_offset);
+int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, off64_t *obj_offset);
-int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos);
+int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, off64_t curpos);
ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len);
void git_packfile_stream_dispose(git_packfile_stream *obj);
-git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs,
- git_off_t *curpos, git_object_t type,
- git_off_t delta_obj_offset);
+int get_delta_base(
+ off64_t *delta_base_out,
+ struct git_pack_file *p,
+ git_mwindow **w_curs,
+ off64_t *curpos,
+ git_object_t type,
+ off64_t delta_obj_offset);
void git_packfile_close(struct git_pack_file *p, bool unlink_packfile);
void git_packfile_free(struct git_pack_file *p);
return 0;
}
+int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx)
+{
+ if (ctx->line_len < GIT_OID_HEXSZ)
+ return -1;
+ if ((git_oid_fromstrn(out, ctx->line, GIT_OID_HEXSZ)) < 0)
+ return -1;
+ git_parse_advance_chars(ctx, GIT_OID_HEXSZ);
+ return 0;
+}
+
int git_parse_peek(char *out, git_parse_ctx *ctx, int flags)
{
size_t remain = ctx->line_len;
size_t line_num;
} git_parse_ctx;
+#define GIT_PARSE_CTX_INIT { 0 }
+
int git_parse_ctx_init(git_parse_ctx *ctx, const char *content, size_t content_len);
void git_parse_ctx_clear(git_parse_ctx *ctx);
-#define git_parse_err(...) \
- ( git_error_set(GIT_ERROR_PATCH, __VA_ARGS__), -1 )
-
#define git_parse_ctx_contains_s(ctx, str) \
git_parse_ctx_contains(ctx, str, sizeof(str) - 1)
int git_parse_advance_ws(git_parse_ctx *ctx);
int git_parse_advance_nl(git_parse_ctx *ctx);
int git_parse_advance_digit(int64_t *out, git_parse_ctx *ctx, int base);
+int git_parse_advance_oid(git_oid *out, git_parse_ctx *ctx);
enum GIT_PARSE_PEEK_FLAGS {
GIT_PARSE_PEEK_SKIP_WHITESPACE = (1 << 0)
git_buf file_header = GIT_BUF_INIT;
if (git_diff_delta__format_file_header(
- &file_header, patch->delta, NULL, NULL, 0) < 0)
+ &file_header, patch->delta, NULL, NULL, 0, true) < 0)
git_error_clear();
else
out += git_buf_len(&file_header);
#include "diff_xdiff.h"
#include "delta.h"
#include "zstream.h"
-#include "fileops.h"
+#include "futils.h"
static void diff_output_init(
git_patch_generated_output *, const git_diff_options *, git_diff_file_cb,
if ((error = git_diff_file_content__load(
&patch->ofile, &patch->base.diff_opts)) < 0 ||
- should_skip_binary(patch, patch->ofile.file))
- goto cleanup;
- if ((error = git_diff_file_content__load(
+ (error = git_diff_file_content__load(
&patch->nfile, &patch->base.diff_opts)) < 0 ||
should_skip_binary(patch, patch->nfile.file))
goto cleanup;
{
git_patch_generated *patch = payload;
git_patch_hunk *hunk;
- git_diff_line *line;
+ git_diff_line *line;
GIT_UNUSED(delta);
GIT_UNUSED(hunk_);
char *old_prefix, *new_prefix;
} git_patch_parsed;
-static int header_path_len(git_patch_parse_ctx *ctx)
+static int git_parse_err(const char *fmt, ...) GIT_FORMAT_PRINTF(1, 2);
+static int git_parse_err(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ git_error_vset(GIT_ERROR_PATCH, fmt, ap);
+ va_end(ap);
+
+ return -1;
+}
+
+static size_t header_path_len(git_patch_parse_ctx *ctx)
{
bool inquote = 0;
bool quoted = git_parse_ctx_contains_s(&ctx->parse_ctx, "\"");
int error;
if ((error = git_buf_put(path, ctx->parse_ctx.line, path_len)) < 0)
- goto done;
+ return error;
git_parse_advance_chars(&ctx->parse_ctx, path_len);
git_buf_rtrim(path);
- if (path->size > 0 && path->ptr[0] == '"')
- error = git_buf_unquote(path);
-
- if (error < 0)
- goto done;
+ if (path->size > 0 && path->ptr[0] == '"' &&
+ (error = git_buf_unquote(path)) < 0)
+ return error;
git_path_squash_slashes(path);
-done:
- return error;
+ if (!path->size)
+ return git_parse_err("patch contains empty path at line %"PRIuZ,
+ ctx->parse_ctx.line_num);
+
+ return 0;
}
static int parse_header_path(char **out, git_patch_parse_ctx *ctx)
{
git_buf path = GIT_BUF_INIT;
- int error = parse_header_path_buf(&path, ctx, header_path_len(ctx));
+ int error;
+ if ((error = parse_header_path_buf(&path, ctx, header_path_len(ctx))) < 0)
+ goto out;
*out = git_buf_detach(&path);
+out:
+ git_buf_dispose(&path);
return error;
}
git_buf old_path = GIT_BUF_INIT;
int error;
+ if (patch->old_path) {
+ error = git_parse_err("patch contains duplicate old path at line %"PRIuZ,
+ ctx->parse_ctx.line_num);
+ goto out;
+ }
+
if ((error = parse_header_path_buf(&old_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
goto out;
git_buf new_path = GIT_BUF_INIT;
int error;
- if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
+ if (patch->new_path) {
+ error = git_parse_err("patch contains duplicate new path at line %"PRIuZ,
+ ctx->parse_ctx.line_num);
goto out;
+ }
+ if ((error = parse_header_path_buf(&new_path, ctx, ctx->parse_ctx.line_len - 1)) < 0)
+ goto out;
patch->new_path = git_buf_detach(&new_path);
out:
return -1;
if (git_parse_peek(&c, &ctx->parse_ctx, 0) == 0 && c == ' ') {
- uint16_t mode;
+ uint16_t mode = 0;
git_parse_advance_chars(&ctx->parse_ctx, 1);
git_patch_parsed *patch,
git_patch_parse_ctx *ctx)
{
- git__free((char *)patch->base.delta->old_file.path);
+ git__free((char *)patch->base.delta->new_file.path);
- patch->base.delta->old_file.path = NULL;
+ patch->base.delta->new_file.path = NULL;
patch->base.delta->status = GIT_DELTA_DELETED;
patch->base.delta->nfiles = 1;
git_patch_parsed *patch,
git_patch_parse_ctx *ctx)
{
- git__free((char *)patch->base.delta->new_file.path);
+ git__free((char *)patch->base.delta->old_file.path);
- patch->base.delta->new_file.path = NULL;
+ patch->base.delta->old_file.path = NULL;
patch->base.delta->status = GIT_DELTA_ADDED;
patch->base.delta->nfiles = 1;
{ "index " , STATE_DIFF, STATE_INDEX, parse_header_git_index },
{ "index " , STATE_END, STATE_INDEX, parse_header_git_index },
+ { "--- " , STATE_DIFF, STATE_PATH, parse_header_git_oldpath },
{ "--- " , STATE_INDEX, STATE_PATH, parse_header_git_oldpath },
+ { "--- " , STATE_FILEMODE, STATE_PATH, parse_header_git_oldpath },
{ "+++ " , STATE_PATH, STATE_END, parse_header_git_newpath },
{ "GIT binary patch" , STATE_INDEX, STATE_END, NULL },
{ "Binary files " , STATE_INDEX, STATE_END, NULL },
+ { "similarity index " , STATE_END, STATE_SIMILARITY, parse_header_similarity },
{ "similarity index " , STATE_DIFF, STATE_SIMILARITY, parse_header_similarity },
{ "dissimilarity index ", STATE_DIFF, STATE_SIMILARITY, parse_header_dissimilarity },
{ "rename from " , STATE_SIMILARITY, STATE_RENAME, parse_header_renamefrom },
/* Next patch */
{ "diff --git " , STATE_END, 0, NULL },
{ "@@ -" , STATE_END, 0, NULL },
+ { "-- " , STATE_INDEX, 0, NULL },
{ "-- " , STATE_END, 0, NULL },
};
static int parse_int(int *out, git_patch_parse_ctx *ctx)
{
- git_off_t num;
+ int64_t num;
if (git_parse_advance_digit(&num, &ctx->parse_ctx, 10) < 0 || !git__is_int(num))
return -1;
return -1;
}
+static int eof_for_origin(int origin) {
+ if (origin == GIT_DIFF_LINE_ADDITION)
+ return GIT_DIFF_LINE_ADD_EOFNL;
+ if (origin == GIT_DIFF_LINE_DELETION)
+ return GIT_DIFF_LINE_DEL_EOFNL;
+ return GIT_DIFF_LINE_CONTEXT_EOFNL;
+}
+
static int parse_hunk_body(
git_patch_parsed *patch,
git_patch_hunk *hunk,
int oldlines = hunk->hunk.old_lines;
int newlines = hunk->hunk.new_lines;
+ int last_origin = 0;
for (;
ctx->parse_ctx.remain_len > 1 &&
!git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -");
git_parse_advance_line(&ctx->parse_ctx)) {
+ int old_lineno, new_lineno, origin, prefix = 1;
char c;
- int origin;
- int prefix = 1;
- int old_lineno = hunk->hunk.old_start + (hunk->hunk.old_lines - oldlines);
- int new_lineno = hunk->hunk.new_start + (hunk->hunk.new_lines - newlines);
+
+ if (git__add_int_overflow(&old_lineno, hunk->hunk.old_start, hunk->hunk.old_lines) ||
+ git__sub_int_overflow(&old_lineno, old_lineno, oldlines) ||
+ git__add_int_overflow(&new_lineno, hunk->hunk.new_start, hunk->hunk.new_lines) ||
+ git__sub_int_overflow(&new_lineno, new_lineno, newlines)) {
+ error = git_parse_err("unrepresentable line count at line %"PRIuZ,
+ ctx->parse_ctx.line_num);
+ goto done;
+ }
if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') {
error = git_parse_err("invalid patch instruction at line %"PRIuZ,
old_lineno = -1;
break;
+ case '\\':
+ /*
+ * If there are no oldlines left, then this is probably
+ * the "\ No newline at end of file" marker. Do not
+ * verify its format, as it may be localized.
+ */
+ if (!oldlines) {
+ prefix = 0;
+ origin = eof_for_origin(last_origin);
+ old_lineno = -1;
+ new_lineno = -1;
+ break;
+ }
+ /* fall through */
+
default:
error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
goto done;
memset(line, 0x0, sizeof(git_diff_line));
- line->content = ctx->parse_ctx.line + prefix;
line->content_len = ctx->parse_ctx.line_len - prefix;
+ line->content = git__strndup(ctx->parse_ctx.line + prefix, line->content_len);
+ GIT_ERROR_CHECK_ALLOC(line->content);
line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
line->origin = origin;
line->num_lines = 1;
line->new_lineno = new_lineno;
hunk->line_count++;
+
+ last_origin = origin;
}
if (oldlines || newlines) {
goto done;
}
- /* Handle "\ No newline at end of file". Only expect the leading
+ /*
+ * Handle "\ No newline at end of file". Only expect the leading
* backslash, though, because the rest of the string could be
* localized. Because `diff` optimizes for the case where you
* want to apply the patch by hand.
line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1);
if (line->content_len < 1) {
- error = git_parse_err("cannot trim trailing newline of empty line");
+ error = git_parse_err("last line has no trailing newline");
goto done;
}
- line->content_len--;
+ line = git_array_alloc(patch->base.lines);
+ GIT_ERROR_CHECK_ALLOC(line);
+
+ memset(line, 0x0, sizeof(git_diff_line));
+
+ line->content_len = ctx->parse_ctx.line_len;
+ line->content = git__strndup(ctx->parse_ctx.line, line->content_len);
+ GIT_ERROR_CHECK_ALLOC(line->content);
+ line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
+ line->origin = eof_for_origin(last_origin);
+ line->num_lines = 1;
+ line->old_lineno = -1;
+ line->new_lineno = -1;
+
+ hunk->line_count++;
git_parse_advance_line(&ctx->parse_ctx);
}
{
git_diff_binary_t type = GIT_DIFF_BINARY_NONE;
git_buf base85 = GIT_BUF_INIT, decoded = GIT_BUF_INIT;
- git_off_t len;
+ int64_t len;
int error = 0;
if (git_parse_ctx_contains_s(&ctx->parse_ctx, "literal ")) {
encoded_len = ((decoded_len / 4) + !!(decoded_len % 4)) * 5;
- if (encoded_len > ctx->parse_ctx.line_len - 1) {
+ if (!encoded_len || !ctx->parse_ctx.line_len || encoded_len > ctx->parse_ctx.line_len - 1) {
error = git_parse_err("truncated binary data at line %"PRIuZ, ctx->parse_ctx.line_num);
goto done;
}
git_patch_parsed *patch,
git_patch_parse_ctx *ctx)
{
+ const char *old = patch->old_path ? patch->old_path : patch->header_old_path;
+ const char *new = patch->new_path ? patch->new_path : patch->header_new_path;
+
+ if (!old || !new)
+ return git_parse_err("corrupt binary data without paths at line %"PRIuZ, ctx->parse_ctx.line_num);
+
+ if (patch->base.delta->status == GIT_DELTA_ADDED)
+ old = "/dev/null";
+ else if (patch->base.delta->status == GIT_DELTA_DELETED)
+ new = "/dev/null";
+
if (git_parse_advance_expected_str(&ctx->parse_ctx, "Binary files ") < 0 ||
- git_parse_advance_expected_str(&ctx->parse_ctx, patch->header_old_path) < 0 ||
- git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 ||
- git_parse_advance_expected_str(&ctx->parse_ctx, patch->header_new_path) < 0 ||
- git_parse_advance_expected_str(&ctx->parse_ctx, " differ") < 0 ||
- git_parse_advance_nl(&ctx->parse_ctx) < 0)
+ git_parse_advance_expected_str(&ctx->parse_ctx, old) < 0 ||
+ git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 ||
+ git_parse_advance_expected_str(&ctx->parse_ctx, new) < 0 ||
+ git_parse_advance_expected_str(&ctx->parse_ctx, " differ") < 0 ||
+ git_parse_advance_nl(&ctx->parse_ctx) < 0)
return git_parse_err("corrupt git binary header at line %"PRIuZ, ctx->parse_ctx.line_num);
patch->base.binary.contains_data = 0;
return parse_patch_hunks(patch, ctx);
}
-int check_header_names(
+static int check_header_names(
const char *one,
const char *two,
const char *old_or_new,
/* Prefer the rename filenames as they are unambiguous and unprefixed */
if (patch->rename_old_path)
patch->base.delta->old_file.path = patch->rename_old_path;
- else
+ else if (prefixed_old)
patch->base.delta->old_file.path = prefixed_old + old_prefixlen;
+ else
+ patch->base.delta->old_file.path = NULL;
if (patch->rename_new_path)
patch->base.delta->new_file.path = patch->rename_new_path;
- else
+ else if (prefixed_new)
patch->base.delta->new_file.path = prefixed_new + new_prefixlen;
+ else
+ patch->base.delta->new_file.path = NULL;
if (!patch->base.delta->old_file.path &&
!patch->base.delta->new_file.path)
static void patch_parsed__free(git_patch *p)
{
git_patch_parsed *patch = (git_patch_parsed *)p;
+ git_diff_line *line;
+ size_t i;
if (!patch)
return;
git__free((char *)patch->base.binary.old_file.data);
git__free((char *)patch->base.binary.new_file.data);
git_array_clear(patch->base.hunks);
+ git_array_foreach(patch->base.lines, i, line)
+ git__free((char *) line->content);
git_array_clear(patch->base.lines);
git__free(patch->base.delta);
#include "win32/w32_buffer.h"
#include "win32/w32_util.h"
#include "win32/version.h"
-#include <AclAPI.h>
+#include <aclapi.h>
#else
#include <dirent.h>
#endif
while (endp > path && *endp == '/')
endp--;
- if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
+ if (endp - path + 1 > INT_MAX) {
+ git_error_set(GIT_ERROR_INVALID, "path too long");
+ len = -1;
+ goto Exit;
+ }
+
+ if ((len = win32_prefix_length(path, (int)(endp - path + 1))) > 0) {
is_prefix = 1;
goto Exit;
}
endp--;
} while (endp > path && *endp == '/');
- if ((len = win32_prefix_length(path, endp - path + 1)) > 0) {
+ if (endp - path + 1 > INT_MAX) {
+ git_error_set(GIT_ERROR_INVALID, "path too long");
+ len = -1;
+ goto Exit;
+ }
+
+ if ((len = win32_prefix_length(path, (int)(endp - path + 1))) > 0) {
is_prefix = 1;
goto Exit;
}
while (path[offset] && path[offset] != '/' && path[offset] != '\\')
offset++;
}
+
+ if (path[offset] == '\\')
+ return offset;
#endif
- if (path[offset] == '/' || path[offset] == '\\')
+ if (path[offset] == '/')
return offset;
return -1; /* Not a real error - signals that path is not rooted */
}
-void git_path_trim_slashes(git_buf *path)
+static void path_trim_slashes(git_buf *path)
{
int ceiling = git_path_root(path->ptr) + 1;
assert(ceiling >= 0);
if (git_buf_puts(&diriter->path_utf8, path) < 0)
return -1;
- git_path_trim_slashes(&diriter->path_utf8);
+ path_trim_slashes(&diriter->path_utf8);
if (diriter->path_utf8.size == 0) {
git_error_set(GIT_ERROR_FILESYSTEM, "could not open directory '%s'", path);
if (git_buf_puts(&diriter->path, path) < 0)
return -1;
- git_path_trim_slashes(&diriter->path);
+ path_trim_slashes(&diriter->path);
if (diriter->path.size == 0) {
git_error_set(GIT_ERROR_FILESYSTEM, "could not open directory '%s'", path);
#endif
if (repo && !protectHFS)
- error = git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS);
+ error = git_repository__configmap_lookup(&protectHFS, repo, GIT_CONFIGMAP_PROTECTHFS);
if (!error && protectHFS)
flags |= GIT_PATH_REJECT_DOT_GIT_HFS;
if (repo)
- error = git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS);
+ error = git_repository__configmap_lookup(&protectNTFS, repo, GIT_CONFIGMAP_PROTECTNTFS);
if (!error && protectNTFS)
flags |= GIT_PATH_REJECT_DOT_GIT_NTFS;
}
}
+bool git_path_supports_symlinks(const char *dir)
+{
+ git_buf path = GIT_BUF_INIT;
+ bool supported = false;
+ struct stat st;
+ int fd;
+
+ if ((fd = git_futils_mktmp(&path, dir, 0666)) < 0 ||
+ p_close(fd) < 0 ||
+ p_unlink(path.ptr) < 0 ||
+ p_symlink("testing", path.ptr) < 0 ||
+ p_lstat(path.ptr, &st) < 0)
+ goto done;
+
+ supported = (S_ISLNK(st.st_mode) != 0);
+done:
+ if (path.size)
+ (void)p_unlink(path.ptr);
+ git_buf_dispose(&path);
+ return supported;
+}
+
int git_path_validate_system_file_ownership(const char *path)
{
#ifndef GIT_WIN32
git_error_set(GIT_ERROR_INVALID, "programdata configuration file owner is not valid");
ret = GIT_ERROR;
}
- free(info);
+ git__free(info);
cleanup:
if (descriptor)
*/
int git_path_normalize_slashes(git_buf *out, const char *path);
+bool git_path_supports_symlinks(const char *dir);
+
/**
* Validate a system file's ownership
*
#include "index.h"
#include "bitvec.h"
#include "diff.h"
+#include "wildmatch.h"
/* what is the common non-wildcard prefix for all items in the pathspec */
char *git_pathspec_prefix(const git_strarray *pathspec)
if (!match)
return -1;
- match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE |
- GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_NOLEADINGDIR;
+ match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG;
ret = git_attr_fnmatch__parse(match, strpool, NULL, &pattern);
if (ret == GIT_ENOTFOUND) {
}
struct pathspec_match_context {
- int fnmatch_flags;
+ int wildmatch_flags;
int (*strcomp)(const char *, const char *);
int (*strncomp)(const char *, const char *, size_t);
};
bool casefold)
{
if (disable_fnmatch)
- ctxt->fnmatch_flags = -1;
+ ctxt->wildmatch_flags = -1;
else if (casefold)
- ctxt->fnmatch_flags = FNM_CASEFOLD;
+ ctxt->wildmatch_flags = WM_CASEFOLD;
else
- ctxt->fnmatch_flags = 0;
+ ctxt->wildmatch_flags = 0;
if (casefold) {
ctxt->strcomp = git__strcasecmp;
struct pathspec_match_context *ctxt,
const char *path)
{
- int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH;
+ int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : WM_NOMATCH;
- if (result == FNM_NOMATCH)
- result = ctxt->strcomp(match->pattern, path) ? FNM_NOMATCH : 0;
+ if (result == WM_NOMATCH)
+ result = ctxt->strcomp(match->pattern, path) ? WM_NOMATCH : 0;
- if (ctxt->fnmatch_flags >= 0 && result == FNM_NOMATCH)
- result = p_fnmatch(match->pattern, path, ctxt->fnmatch_flags);
+ if (ctxt->wildmatch_flags >= 0 && result == WM_NOMATCH)
+ result = wildmatch(match->pattern, path, ctxt->wildmatch_flags);
/* if we didn't match, look for exact dirname prefix match */
- if (result == FNM_NOMATCH &&
+ if (result == WM_NOMATCH &&
(match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 &&
ctxt->strncomp(path, match->pattern, match->length) == 0 &&
path[match->length] == '/')
/* if we didn't match and this is a negative match, check for exact
* match of filename with leading '!'
*/
- if (result == FNM_NOMATCH &&
+ if (result == WM_NOMATCH &&
(match->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0 &&
*path == '!' &&
ctxt->strncomp(path + 1, match->pattern, match->length) == 0 &&
memset(ps, 0, sizeof(*ps));
ps->prefix = git_pathspec_prefix(paths);
- git_pool_init(&ps->pool, 1);
- if ((error = git_pathspec__vinit(&ps->pathspec, paths, &ps->pool)) < 0)
+ if ((error = git_pool_init(&ps->pool, 1)) < 0 ||
+ (error = git_pathspec__vinit(&ps->pathspec, paths, &ps->pool)) < 0)
git_pathspec__clear(ps);
return error;
if (!m)
return NULL;
- git_pool_init(&m->pool, 1);
+ if (git_pool_init(&m->pool, 1) < 0)
+ return NULL;
/* need to keep reference to pathspec and increment refcount because
* failures array stores pointers to the pattern strings of the
if ((error = git_iterator_reset_range(iter, ps->prefix, ps->prefix)) < 0)
goto done;
- if (git_iterator_type(iter) == GIT_ITERATOR_TYPE_WORKDIR &&
+ if (git_iterator_type(iter) == GIT_ITERATOR_WORKDIR &&
(error = git_repository_index__weakptr(
&index, git_iterator_owner(iter))) < 0)
goto done;
struct git_pool_page {
git_pool_page *next;
- uint32_t size;
- uint32_t avail;
+ size_t size;
+ size_t avail;
GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8);
};
-static void *pool_alloc_page(git_pool *pool, uint32_t size);
+static void *pool_alloc_page(git_pool *pool, size_t size);
-uint32_t git_pool__system_page_size(void)
-{
- static uint32_t size = 0;
+#ifndef GIT_DEBUG_POOL
- if (!size) {
- size_t page_size;
- if (git__page_size(&page_size) < 0)
- page_size = 4096;
- /* allow space for malloc overhead */
- size = page_size - (2 * sizeof(void *)) - sizeof(git_pool_page);
- }
+static size_t system_page_size = 0;
- return size;
+int git_pool_global_init(void)
+{
+ if (git__page_size(&system_page_size) < 0)
+ system_page_size = 4096;
+ /* allow space for malloc overhead */
+ system_page_size -= (2 * sizeof(void *)) + sizeof(git_pool_page);
+ return 0;
}
-#ifndef GIT_DEBUG_POOL
-void git_pool_init(git_pool *pool, uint32_t item_size)
+int git_pool_init(git_pool *pool, size_t item_size)
{
assert(pool);
assert(item_size >= 1);
memset(pool, 0, sizeof(git_pool));
pool->item_size = item_size;
- pool->page_size = git_pool__system_page_size();
+ pool->page_size = system_page_size;
+
+ return 0;
}
void git_pool_clear(git_pool *pool)
pool->pages = NULL;
}
-static void *pool_alloc_page(git_pool *pool, uint32_t size)
+static void *pool_alloc_page(git_pool *pool, size_t size)
{
git_pool_page *page;
- const uint32_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
+ const size_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
size_t alloc_size;
if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
return page->data;
}
-static void *pool_alloc(git_pool *pool, uint32_t size)
+static void *pool_alloc(git_pool *pool, size_t size)
{
git_pool_page *page = pool->pages;
void *ptr = NULL;
#else
+int git_pool_global_init(void)
+{
+ return 0;
+}
+
static int git_pool__ptr_cmp(const void * a, const void * b)
{
if(a > b) {
}
}
-void git_pool_init(git_pool *pool, uint32_t item_size)
+int git_pool_init(git_pool *pool, size_t item_size)
{
assert(pool);
assert(item_size >= 1);
pool->item_size = item_size;
pool->page_size = git_pool__system_page_size();
git_vector_init(&pool->allocations, 100, git_pool__ptr_cmp);
+
+ return 0;
}
void git_pool_clear(git_pool *pool)
git_vector_free_deep(&pool->allocations);
}
-static void *pool_alloc(git_pool *pool, uint32_t size) {
+static void *pool_alloc(git_pool *pool, size_t size) {
void *ptr = NULL;
if((ptr = git__malloc(size)) == NULL) {
return NULL;
memcpy(b, &temp, sizeof(temp));
}
-static uint32_t alloc_size(git_pool *pool, uint32_t count)
+static size_t alloc_size(git_pool *pool, size_t count)
{
- const uint32_t align = sizeof(void *) - 1;
+ const size_t align = sizeof(void *) - 1;
if (pool->item_size > 1) {
- const uint32_t item_size = (pool->item_size + align) & ~align;
+ const size_t item_size = (pool->item_size + align) & ~align;
return item_size * count;
}
return (count + align) & ~align;
}
-void *git_pool_malloc(git_pool *pool, uint32_t items)
+void *git_pool_malloc(git_pool *pool, size_t items)
{
return pool_alloc(pool, alloc_size(pool, items));
}
-void *git_pool_mallocz(git_pool *pool, uint32_t items)
+void *git_pool_mallocz(git_pool *pool, size_t items)
{
- const uint32_t size = alloc_size(pool, items);
+ const size_t size = alloc_size(pool, items);
void *ptr = pool_alloc(pool, size);
if (ptr)
memset(ptr, 0x0, size);
assert(pool && str && pool->item_size == sizeof(char));
- if ((uint32_t)(n + 1) < n)
+ if (n == SIZE_MAX)
return NULL;
- if ((ptr = git_pool_malloc(pool, (uint32_t)(n + 1))) != NULL) {
+ if ((ptr = git_pool_malloc(pool, (n + 1))) != NULL) {
memcpy(ptr, str, n);
ptr[n] = '\0';
}
char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
{
void *ptr;
- size_t len_a, len_b;
+ size_t len_a, len_b, total;
assert(pool && pool->item_size == sizeof(char));
len_a = a ? strlen(a) : 0;
len_b = b ? strlen(b) : 0;
- if ((ptr = git_pool_malloc(pool, (uint32_t)(len_a + len_b + 1))) != NULL) {
+ if (GIT_ADD_SIZET_OVERFLOW(&total, len_a, len_b) ||
+ GIT_ADD_SIZET_OVERFLOW(&total, total, 1))
+ return NULL;
+
+ if ((ptr = git_pool_malloc(pool, total)) != NULL) {
if (len_a)
memcpy(ptr, a, len_a);
if (len_b)
*/
typedef struct {
git_pool_page *pages; /* allocated pages */
- uint32_t item_size; /* size of single alloc unit in bytes */
- uint32_t page_size; /* size of page in bytes */
+ size_t item_size; /* size of single alloc unit in bytes */
+ size_t page_size; /* size of page in bytes */
} git_pool;
#define GIT_POOL_INIT { NULL, 0, 0 }
*/
typedef struct {
git_vector allocations;
- uint32_t item_size;
- uint32_t page_size;
+ size_t item_size;
+ size_t page_size;
} git_pool;
#define GIT_POOL_INIT { GIT_VECTOR_INIT, 0, 0 }
* Of course, you can use this in other ways, but those are the
* two most common patterns.
*/
-extern void git_pool_init(git_pool *pool, uint32_t item_size);
+extern int git_pool_init(git_pool *pool, size_t item_size);
/**
* Free all items in pool
/**
* Allocate space for one or more items from a pool.
*/
-extern void *git_pool_malloc(git_pool *pool, uint32_t items);
-extern void *git_pool_mallocz(git_pool *pool, uint32_t items);
+extern void *git_pool_malloc(git_pool *pool, size_t items);
+extern void *git_pool_mallocz(git_pool *pool, size_t items);
/**
* Allocate space and duplicate string data into it.
#endif
extern bool git_pool__ptr_in_pool(git_pool *pool, void *ptr);
+/**
+ * This function is being called by our global setup routines to
+ * initialize the system pool size.
+ *
+ * @return 0 on success, <0 on failure
+ */
+extern int git_pool_global_init(void);
+
#endif
GIT_UNUSED(hints);
- if ((ainfo = malloc(sizeof(struct addrinfo))) == NULL)
+ if ((ainfo = git__malloc(sizeof(struct addrinfo))) == NULL)
return -1;
if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) {
- free(ainfo);
+ git__free(ainfo);
return -2;
}
ai = ainfo;
for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) {
- if (!(ai->ai_next = malloc(sizeof(struct addrinfo)))) {
+ if (!(ai->ai_next = git__malloc(sizeof(struct addrinfo)))) {
p_freeaddrinfo(ainfo);
return -1;
}
while(p != NULL) {
next = p->ai_next;
- free(p);
+ git__free(p);
p = next;
}
}
}
-int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
+int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
{
GIT_MMAP_VALIDATE(out, len, prot, flags);
return -1;
}
- out->data = malloc(len);
+ out->data = git__malloc(len);
GIT_ERROR_CHECK_ALLOC(out->data);
if (!git__is_ssizet(len) ||
int p_munmap(git_map *map)
{
assert(map != NULL);
- free(map->data);
+ git__free(map->data);
return 0;
}
#include <fcntl.h>
#include <time.h>
-#include "fnmatch.h"
/* stat: file mode type testing macros */
#ifndef S_IFGITLINK
#define EAFNOSUPPORT (INT_MAX-1)
#endif
+/* Provide a 64-bit size for offsets. */
+
+#if defined(_MSC_VER)
+typedef __int64 off64_t;
+#elif defined(__HAIKU__)
+typedef __haiku_std_int64 off64_t;
+#elif defined(__APPLE__)
+typedef __int64_t off64_t;
+#else
+typedef int64_t off64_t;
+#endif
+
typedef int git_file;
/**
#include "git2/proxy.h"
-int git_proxy_init_options(git_proxy_options *opts, unsigned int version)
+int git_proxy_options_init(git_proxy_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_proxy_options, GIT_PROXY_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_proxy_init_options(git_proxy_options *opts, unsigned int version)
+{
+ return git_proxy_options_init(opts, version);
+}
+#endif
+
int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src)
{
if (!src) {
- git_proxy_init_options(tgt, GIT_PROXY_OPTIONS_VERSION);
+ git_proxy_options_init(tgt, GIT_PROXY_OPTIONS_VERSION);
return 0;
}
continue;
/* Update the remote ref */
- if (git_oid_iszero(&push_spec->loid)) {
+ if (git_oid_is_zero(&push_spec->loid)) {
error = git_reference_lookup(&remote_ref, push->remote->repo, git_buf_cstr(&remote_ref_name));
if (error >= 0) {
git_object_t type;
size_t size;
- if (git_oid_iszero(&spec->loid))
+ if (git_oid_is_zero(&spec->loid))
/*
* Delete reference on remote side;
* nothing to do here.
if (!spec->refspec.force) {
git_oid base;
- if (git_oid_iszero(&spec->roid))
+ if (git_oid_is_zero(&spec->roid))
continue;
if (!git_odb_exists(push->repo->_odb, &spec->roid)) {
}
git_vector_foreach(&push->remote->refs, i, head) {
- if (git_oid_iszero(&head->oid))
+ if (git_oid_is_zero(&head->oid))
continue;
- /* TODO */
- git_revwalk_hide(rw, &head->oid);
+ if ((error = git_revwalk_hide(rw, &head->oid)) < 0 &&
+ error != GIT_ENOTFOUND && error != GIT_EINVALIDSPEC && error != GIT_EPEEL)
+ goto on_error;
}
error = git_packbuilder_insert_walk(push->pb, rw);
git__free(push);
}
-int git_push_init_options(git_push_options *opts, unsigned int version)
+int git_push_options_init(git_push_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_push_options, GIT_PUSH_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_push_init_options(git_push_options *opts, unsigned int version)
+{
+ return git_push_options_init(opts, version);
+}
+#endif
#include "reader.h"
-#include "fileops.h"
+#include "futils.h"
#include "blob.h"
#include "git2/tree.h"
tree_reader *reader = (tree_reader *)_reader;
git_tree_entry *tree_entry = NULL;
git_blob *blob = NULL;
- git_off_t blobsize;
+ git_object_size_t blobsize;
int error;
if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 ||
#define REBASE_FILE_MODE 0666
typedef enum {
- GIT_REBASE_TYPE_NONE = 0,
- GIT_REBASE_TYPE_APPLY = 1,
- GIT_REBASE_TYPE_MERGE = 2,
- GIT_REBASE_TYPE_INTERACTIVE = 3,
-} git_rebase_type_t;
+ GIT_REBASE_NONE = 0,
+ GIT_REBASE_APPLY = 1,
+ GIT_REBASE_MERGE = 2,
+ GIT_REBASE_INTERACTIVE = 3,
+} git_rebase_t;
struct git_rebase {
git_repository *repo;
git_rebase_options options;
- git_rebase_type_t type;
+ git_rebase_t type;
char *state_path;
int head_detached : 1,
#define GIT_REBASE_STATE_INIT {0}
static int rebase_state_type(
- git_rebase_type_t *type_out,
+ git_rebase_t *type_out,
char **path_out,
git_repository *repo)
{
git_buf path = GIT_BUF_INIT;
- git_rebase_type_t type = GIT_REBASE_TYPE_NONE;
+ git_rebase_t type = GIT_REBASE_NONE;
if (git_buf_joinpath(&path, repo->gitdir, REBASE_APPLY_DIR) < 0)
return -1;
if (git_path_isdir(git_buf_cstr(&path))) {
- type = GIT_REBASE_TYPE_APPLY;
+ type = GIT_REBASE_APPLY;
goto done;
}
return -1;
if (git_path_isdir(git_buf_cstr(&path))) {
- type = GIT_REBASE_TYPE_MERGE;
+ type = GIT_REBASE_MERGE;
goto done;
}
done:
*type_out = type;
- if (type != GIT_REBASE_TYPE_NONE && path_out)
+ if (type != GIT_REBASE_NONE && path_out)
*path_out = git_buf_detach(&path);
git_buf_dispose(&path);
if (rebase_opts)
memcpy(&rebase->options, rebase_opts, sizeof(git_rebase_options));
else
- git_rebase_init_options(&rebase->options, GIT_REBASE_OPTIONS_VERSION);
+ git_rebase_options_init(&rebase->options, GIT_REBASE_OPTIONS_VERSION);
if (rebase_opts && rebase_opts->rewrite_notes_ref) {
rebase->options.rewrite_notes_ref = git__strdup(rebase_opts->rewrite_notes_ref);
git_rebase *rebase;
git_buf path = GIT_BUF_INIT, orig_head_name = GIT_BUF_INIT,
orig_head_id = GIT_BUF_INIT, onto_id = GIT_BUF_INIT;
- int state_path_len, error;
+ size_t state_path_len;
+ int error;
assert(repo);
if ((error = rebase_state_type(&rebase->type, &rebase->state_path, repo)) < 0)
goto done;
- if (rebase->type == GIT_REBASE_TYPE_NONE) {
+ if (rebase->type == GIT_REBASE_NONE) {
git_error_set(GIT_ERROR_REBASE, "there is no rebase in progress");
error = GIT_ENOTFOUND;
goto done;
rebase->orig_head_name = git_buf_detach(&orig_head_name);
switch (rebase->type) {
- case GIT_REBASE_TYPE_INTERACTIVE:
+ case GIT_REBASE_INTERACTIVE:
git_error_set(GIT_ERROR_REBASE, "interactive rebase is not supported");
error = -1;
break;
- case GIT_REBASE_TYPE_MERGE:
+ case GIT_REBASE_MERGE:
error = rebase_open_merge(rebase);
break;
- case GIT_REBASE_TYPE_APPLY:
+ case GIT_REBASE_APPLY:
git_error_set(GIT_ERROR_REBASE, "patch application rebase is not supported");
error = -1;
break;
return rebase_setupfiles_merge(rebase);
}
-int git_rebase_init_options(git_rebase_options *opts, unsigned int version)
+int git_rebase_options_init(git_rebase_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_rebase_options, GIT_REBASE_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_rebase_init_options(git_rebase_options *opts, unsigned int version)
+{
+ return git_rebase_options_init(opts, version);
+}
+#endif
+
static int rebase_ensure_not_in_progress(git_repository *repo)
{
int error;
- git_rebase_type_t type;
+ git_rebase_t type;
if ((error = rebase_state_type(&type, NULL, repo)) < 0)
return error;
- if (type != GIT_REBASE_TYPE_NONE) {
+ if (type != GIT_REBASE_NONE) {
git_error_set(GIT_ERROR_REBASE, "there is an existing rebase in progress");
return -1;
}
rebase->repo = repo;
rebase->inmemory = inmemory;
- rebase->type = GIT_REBASE_TYPE_MERGE;
+ rebase->type = GIT_REBASE_MERGE;
if ((error = rebase_init_operations(rebase, repo, branch, upstream, onto)) < 0)
goto done;
if (!checkout_opts->ancestor_label)
checkout_opts->ancestor_label = "ancestor";
- if (rebase->type == GIT_REBASE_TYPE_MERGE) {
+ if (rebase->type == GIT_REBASE_MERGE) {
if (!checkout_opts->our_label)
checkout_opts->our_label = rebase->onto_name;
if (rebase->inmemory)
error = rebase_next_inmemory(out, rebase);
- else if (rebase->type == GIT_REBASE_TYPE_MERGE)
+ else if (rebase->type == GIT_REBASE_MERGE)
error = rebase_next_merge(out, rebase);
else
abort();
git_commit *current_commit = NULL, *commit = NULL;
git_tree *parent_tree = NULL, *tree = NULL;
git_oid tree_id, commit_id;
+ git_buf commit_content = GIT_BUF_INIT, commit_signature = GIT_BUF_INIT,
+ signature_field = GIT_BUF_INIT;
+ const char *signature_field_string = NULL,
+ *commit_signature_string = NULL;
int error;
operation = git_array_get(rebase->operations, rebase->current);
message = git_commit_message(current_commit);
}
- if ((error = git_commit_create(&commit_id, rebase->repo, NULL, author,
- committer, message_encoding, message, tree, 1,
- (const git_commit **)&parent_commit)) < 0 ||
- (error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0)
+ if ((error = git_commit_create_buffer(&commit_content, rebase->repo, author, committer,
+ message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0)
+ goto done;
+
+ if (rebase->options.signing_cb) {
+ git_error_clear();
+ error = git_error_set_after_callback_function(rebase->options.signing_cb(
+ &commit_signature, &signature_field, git_buf_cstr(&commit_content),
+ rebase->options.payload), "commit signing_cb failed");
+ if (error == GIT_PASSTHROUGH) {
+ git_buf_dispose(&commit_signature);
+ git_buf_dispose(&signature_field);
+ git_error_clear();
+ error = GIT_OK;
+ } else if (error < 0)
+ goto done;
+ }
+
+ if (git_buf_is_allocated(&commit_signature)) {
+ assert(git_buf_contains_nul(&commit_signature));
+ commit_signature_string = git_buf_cstr(&commit_signature);
+ }
+
+ if (git_buf_is_allocated(&signature_field)) {
+ assert(git_buf_contains_nul(&signature_field));
+ signature_field_string = git_buf_cstr(&signature_field);
+ }
+
+ if ((error = git_commit_create_with_signature(&commit_id, rebase->repo,
+ git_buf_cstr(&commit_content), commit_signature_string,
+ signature_field_string)))
+ goto done;
+
+ if ((error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0)
goto done;
*out = commit;
if (error < 0)
git_commit_free(commit);
+ git_buf_dispose(&commit_signature);
+ git_buf_dispose(&signature_field);
+ git_buf_dispose(&commit_content);
git_commit_free(current_commit);
git_tree_free(parent_tree);
git_tree_free(tree);
if (rebase->inmemory)
error = rebase_commit_inmemory(
id, rebase, author, committer, message_encoding, message);
- else if (rebase->type == GIT_REBASE_TYPE_MERGE)
+ else if (rebase->type == GIT_REBASE_MERGE)
error = rebase_commit_merge(
id, rebase, author, committer, message_encoding, message);
else
return error;
}
+const char *git_rebase_orig_head_name(git_rebase *rebase) {
+ return rebase->orig_head_name;
+}
+
+const git_oid *git_rebase_orig_head_id(git_rebase *rebase) {
+ return &rebase->orig_head_id;
+}
+
+const char *git_rebase_onto_name(git_rebase *rebase) {
+ return rebase->onto_name;
+}
+
+const git_oid *git_rebase_onto_id(git_rebase *rebase) {
+ return &rebase->onto_id;
+}
+
size_t git_rebase_operation_entrycount(git_rebase *rebase)
{
assert(rebase);
#include "reflog.h"
#include "posix.h"
+#define DEFAULT_NESTING_LEVEL 5
+#define MAX_NESTING_LEVEL 10
+
int git_refdb_new(git_refdb **out, git_repository *repo)
{
git_refdb *db;
int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
{
+ GIT_ERROR_CHECK_VERSION(backend, GIT_REFDB_BACKEND_VERSION, "git_refdb_backend");
+
+ if (!backend->exists || !backend->lookup || !backend->iterator ||
+ !backend->write || !backend->rename || !backend->del ||
+ !backend->has_log || !backend->ensure_log || !backend->free ||
+ !backend->reflog_read || !backend->reflog_write ||
+ !backend->reflog_rename || !backend->reflog_delete ||
+ (backend->lock && !backend->unlock)) {
+ git_error_set(GIT_ERROR_REFERENCE, "incomplete refdb backend implementation");
+ return GIT_EINVALID;
+ }
+
refdb_free_backend(db);
db->backend = backend;
return 0;
}
+int git_refdb_resolve(
+ git_reference **out,
+ git_refdb *db,
+ const char *ref_name,
+ int max_nesting)
+{
+ git_reference *ref = NULL;
+ int error = 0, nesting;
+
+ *out = NULL;
+
+ if (max_nesting > MAX_NESTING_LEVEL)
+ max_nesting = MAX_NESTING_LEVEL;
+ else if (max_nesting < 0)
+ max_nesting = DEFAULT_NESTING_LEVEL;
+
+ if ((error = git_refdb_lookup(&ref, db, ref_name)) < 0)
+ goto out;
+
+ for (nesting = 0; nesting < max_nesting; nesting++) {
+ git_reference *resolved;
+
+ if (ref->type == GIT_REFERENCE_DIRECT)
+ break;
+
+ if ((error = git_refdb_lookup(&resolved, db, git_reference_symbolic_target(ref))) < 0) {
+ /* If we found a symbolic reference with a nonexistent target, return it. */
+ if (error == GIT_ENOTFOUND) {
+ error = 0;
+ *out = ref;
+ ref = NULL;
+ }
+ goto out;
+ }
+
+ git_reference_free(ref);
+ ref = resolved;
+ }
+
+ if (ref->type != GIT_REFERENCE_DIRECT && max_nesting != 0) {
+ git_error_set(GIT_ERROR_REFERENCE,
+ "cannot resolve reference (>%u levels deep)", max_nesting);
+ error = -1;
+ goto out;
+ }
+
+ *out = ref;
+ ref = NULL;
+out:
+ git_reference_free(ref);
+ return error;
+}
+
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
{
int error;
return 0;
}
+int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference *ref)
+{
+ int error, logall;
+
+ error = git_repository__configmap_lookup(&logall, db->repo, GIT_CONFIGMAP_LOGALLREFUPDATES);
+ if (error < 0)
+ return error;
+
+ /* Defaults to the opposite of the repo being bare */
+ if (logall == GIT_LOGALLREFUPDATES_UNSET)
+ logall = !git_repository_is_bare(db->repo);
+
+ *out = 0;
+ switch (logall) {
+ case GIT_LOGALLREFUPDATES_FALSE:
+ *out = 0;
+ break;
+
+ case GIT_LOGALLREFUPDATES_TRUE:
+ /* Only write if it already has a log,
+ * or if it's under heads/, remotes/ or notes/
+ */
+ *out = git_refdb_has_log(db, ref->name) ||
+ !git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) ||
+ !git__strcmp(ref->name, GIT_HEAD_FILE) ||
+ !git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) ||
+ !git__prefixcmp(ref->name, GIT_REFS_NOTES_DIR);
+ break;
+
+ case GIT_LOGALLREFUPDATES_ALWAYS:
+ *out = 1;
+ break;
+ }
+
+ return 0;
+}
+
+int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref)
+{
+ git_reference *head = NULL, *resolved = NULL;
+ const char *name;
+ int error;
+
+ *out = 0;
+
+ if (ref->type == GIT_REFERENCE_SYMBOLIC) {
+ error = 0;
+ goto out;
+ }
+
+ if ((error = git_refdb_lookup(&head, db, GIT_HEAD_FILE)) < 0)
+ goto out;
+
+ if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
+ goto out;
+
+ /* Go down the symref chain until we find the branch */
+ if ((error = git_refdb_resolve(&resolved, db, git_reference_symbolic_target(head), -1)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto out;
+ error = 0;
+ name = git_reference_symbolic_target(head);
+ } else if (git_reference_type(resolved) == GIT_REFERENCE_SYMBOLIC) {
+ name = git_reference_symbolic_target(resolved);
+ } else {
+ name = git_reference_name(resolved);
+ }
+
+ if (strcmp(name, ref->name))
+ goto out;
+
+ *out = 1;
+
+out:
+ git_reference_free(resolved);
+ git_reference_free(head);
+ return error;
+}
+
int git_refdb_has_log(git_refdb *db, const char *refname)
{
assert(db && refname);
git_refdb *refdb,
const char *ref_name);
+/**
+ * Resolve the reference by following symbolic references.
+ *
+ * Given a reference name, this function will follow any symbolic references up
+ * to `max_nesting` deep and return the resolved direct reference. If any of
+ * the intermediate symbolic references points to a non-existing reference,
+ * then that symbolic reference is returned instead with an error code of `0`.
+ * If the given reference is a direct reference already, it is returned
+ * directly.
+ *
+ * If `max_nesting` is `0`, the reference will not be resolved. If it's
+ * negative, it will be set to the default resolve depth which is `5`.
+ *
+ * @param out Pointer to store the result in.
+ * @param db The refdb to use for resolving the reference.
+ * @param ref_name The reference name to lookup and resolve.
+ * @param max_nesting The maximum nesting depth.
+ * @return `0` on success, a negative error code otherwise.
+ */
+int git_refdb_resolve(
+ git_reference **out,
+ git_refdb *db,
+ const char *ref_name,
+ int max_nesting);
+
int git_refdb_rename(
git_reference **out,
git_refdb *db,
int git_refdb_reflog_read(git_reflog **out, git_refdb *db, const char *name);
int git_refdb_reflog_write(git_reflog *reflog);
+/**
+ * Determine whether a reflog entry should be created for the given reference.
+ *
+ * Whether or not writing to a reference should create a reflog entry is
+ * dependent on a number of things. Most importantly, there's the
+ * "core.logAllRefUpdates" setting that controls in which situations a
+ * reference should get a corresponding reflog entry. The following values for
+ * it are understood:
+ *
+ * - "false": Do not log reference updates.
+ *
+ * - "true": Log normal reference updates. This will write entries for
+ * references in "refs/heads", "refs/remotes", "refs/notes" and
+ * "HEAD" or if the reference already has a log entry.
+ *
+ * - "always": Always create a reflog entry.
+ *
+ * If unset, the value will default to "true" for non-bare repositories and
+ * "false" for bare ones.
+ *
+ * @param out pointer to which the result will be written, `1` means a reflog
+ * entry should be written, `0` means none should be written.
+ * @param db The refdb to decide this for.
+ * @param ref The reference one wants to check.
+ * @return `0` on success, a negative error code otherwise.
+ */
+int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference *ref);
+
+/**
+ * Determine whether a reflog entry should be created for HEAD if creating one
+ * for the given reference
+ *
+ * In case the given reference is being pointed to by HEAD, then creating a
+ * reflog entry for this reference also requires us to create a corresponding
+ * reflog entry for HEAD. This function can be used to determine that scenario.
+ *
+ * @param out pointer to which the result will be written, `1` means a reflog
+ * entry should be written, `0` means none should be written.
+ * @param db The refdb to decide this for.
+ * @param ref The reference one wants to check.
+ * @return `0` on success, a negative error code otherwise.
+ */
+int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref);
+
int git_refdb_has_log(git_refdb *db, const char *refname);
int git_refdb_ensure_log(git_refdb *refdb, const char *refname);
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "refdb_fs.h"
-
#include "refs.h"
#include "hash.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "filebuf.h"
#include "pack.h"
+#include "parse.h"
#include "reflog.h"
#include "refdb.h"
#include "iterator.h"
#include "sortedcache.h"
#include "signature.h"
+#include "wildmatch.h"
#include <git2/tag.h>
#include <git2/object.h>
git_refdb_backend *_backend,
const char *ref_name)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
git_buf ref_path = GIT_BUF_INIT;
int error;
assert(backend);
- if ((error = packed_reload(backend)) < 0 ||
- (error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
- return error;
+ *exists = 0;
+
+ if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
+ goto out;
- *exists = git_path_isfile(ref_path.ptr) ||
- (git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
+ if (git_path_isfile(ref_path.ptr)) {
+ *exists = 1;
+ goto out;
+ }
+
+ if ((error = packed_reload(backend)) < 0)
+ goto out;
+
+ if (git_sortedcache_lookup(backend->refcache, ref_name) != NULL) {
+ *exists = 1;
+ goto out;
+ }
+out:
git_buf_dispose(&ref_path);
- return 0;
+ return error;
}
static const char *loose_parse_symbolic(git_buf *file_content)
git_refdb_backend *_backend,
const char *ref_name)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
int error;
assert(backend);
static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
{
- refdb_fs_iter *iter = (refdb_fs_iter *) _iter;
+ refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent);
git_vector_free(&iter->loose);
git_pool_clear(&iter->pool);
while (!error && !git_iterator_advance(&entry, fsit)) {
const char *ref_name;
- struct packref *ref;
char *ref_dup;
git_buf_truncate(&path, ref_prefix_len);
ref_name = git_buf_cstr(&path);
if (git__suffixcmp(ref_name, ".lock") == 0 ||
- (iter->glob && p_fnmatch(iter->glob, ref_name, 0) != 0))
+ (iter->glob && wildmatch(iter->glob, ref_name, 0) != 0))
continue;
- git_sortedcache_rlock(backend->refcache);
- ref = git_sortedcache_lookup(backend->refcache, ref_name);
- if (ref)
- ref->flags |= PACKREF_SHADOWED;
- git_sortedcache_runlock(backend->refcache);
-
ref_dup = git_pool_strdup(&iter->pool, ref_name);
if (!ref_dup)
error = -1;
git_reference **out, git_reference_iterator *_iter)
{
int error = GIT_ITEROVER;
- refdb_fs_iter *iter = (refdb_fs_iter *)_iter;
- refdb_fs_backend *backend = (refdb_fs_backend *)iter->parent.db->backend;
+ refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent);
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(iter->parent.db->backend, refdb_fs_backend, parent);
struct packref *ref;
while (iter->loose_pos < iter->loose.length) {
const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
- if (loose_lookup(out, backend, path) == 0)
+ if (loose_lookup(out, backend, path) == 0) {
+ ref = git_sortedcache_lookup(iter->cache, path);
+ if (ref)
+ ref->flags |= PACKREF_SHADOWED;
+
return 0;
+ }
git_error_clear();
}
- if (!iter->cache) {
- if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
- return error;
- }
-
error = GIT_ITEROVER;
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
if (ref->flags & PACKREF_SHADOWED)
continue;
- if (iter->glob && p_fnmatch(iter->glob, ref->name, 0) != 0)
+ if (iter->glob && wildmatch(iter->glob, ref->name, 0) != 0)
continue;
*out = git_reference__alloc(ref->name, &ref->oid, &ref->peel);
const char **out, git_reference_iterator *_iter)
{
int error = GIT_ITEROVER;
- refdb_fs_iter *iter = (refdb_fs_iter *)_iter;
- refdb_fs_backend *backend = (refdb_fs_backend *)iter->parent.db->backend;
+ refdb_fs_iter *iter = GIT_CONTAINER_OF(_iter, refdb_fs_iter, parent);
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(iter->parent.db->backend, refdb_fs_backend, parent);
struct packref *ref;
while (iter->loose_pos < iter->loose.length) {
const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
+ struct packref *ref;
if (loose_lookup(NULL, backend, path) == 0) {
+ ref = git_sortedcache_lookup(iter->cache, path);
+ if (ref)
+ ref->flags |= PACKREF_SHADOWED;
+
*out = path;
return 0;
}
git_error_clear();
}
- if (!iter->cache) {
- if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
- return error;
- }
-
error = GIT_ITEROVER;
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
if (ref->flags & PACKREF_SHADOWED)
continue;
- if (iter->glob && p_fnmatch(iter->glob, ref->name, 0) != 0)
+ if (iter->glob && wildmatch(iter->glob, ref->name, 0) != 0)
continue;
*out = ref->name;
static int refdb_fs_backend__iterator(
git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
{
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
+ refdb_fs_iter *iter = NULL;
int error;
- refdb_fs_iter *iter;
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
assert(backend);
- if ((error = packed_reload(backend)) < 0)
- return error;
-
iter = git__calloc(1, sizeof(refdb_fs_iter));
GIT_ERROR_CHECK_ALLOC(iter);
- git_pool_init(&iter->pool, 1);
+ if ((error = git_pool_init(&iter->pool, 1)) < 0)
+ goto out;
- if (git_vector_init(&iter->loose, 8, NULL) < 0)
- goto fail;
+ if ((error = git_vector_init(&iter->loose, 8, NULL)) < 0)
+ goto out;
if (glob != NULL &&
- (iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL)
- goto fail;
+ (iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL) {
+ error = GIT_ERROR_NOMEMORY;
+ goto out;
+ }
+
+ if ((error = iter_load_loose_paths(backend, iter)) < 0)
+ goto out;
+
+ if ((error = packed_reload(backend)) < 0)
+ goto out;
+
+ if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
+ goto out;
iter->parent.next = refdb_fs_backend__iterator_next;
iter->parent.next_name = refdb_fs_backend__iterator_next_name;
iter->parent.free = refdb_fs_backend__iterator_free;
- if (iter_load_loose_paths(backend, iter) < 0)
- goto fail;
-
*out = (git_reference_iterator *)iter;
- return 0;
-
-fail:
- refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
- return -1;
+out:
+ if (error)
+ refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
+ return error;
}
static bool ref_is_available(
if (git_buf_joinpath(&ref_path, basedir, name) < 0)
return -1;
- filebuf_flags = GIT_FILEBUF_FORCE;
+ filebuf_flags = GIT_FILEBUF_CREATE_LEADING_DIRS;
if (backend->fsync)
filebuf_flags |= GIT_FILEBUF_FSYNC;
{
int error;
git_filebuf *lock;
- refdb_fs_backend *backend = (refdb_fs_backend *) _backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
lock = git__calloc(1, sizeof(git_filebuf));
GIT_ERROR_CHECK_ALLOC(lock);
const git_reference *ref,
git_filebuf *file,
int update_reflog,
- const git_signature *who,
- const char *message,
const git_oid *old_id,
- const char *old_target);
+ const char *old_target,
+ const git_signature *who,
+ const char *message);
static int refdb_fs_backend__delete_tail(
git_refdb_backend *_backend,
git_filebuf *file,
const char *ref_name,
- const git_oid *old_id, const char *old_target);
+ const git_oid *old_id,
+ const char *old_target);
static int refdb_fs_backend__unlock(git_refdb_backend *backend, void *payload, int success, int update_reflog,
const git_reference *ref, const git_signature *sig, const char *message)
if (success == 2)
error = refdb_fs_backend__delete_tail(backend, lock, ref->name, NULL, NULL);
else if (success)
- error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, sig, message, NULL, NULL);
+ error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, NULL, NULL, sig, message);
else
git_filebuf_cleanup(lock);
return error;
}
-static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message);
-static int has_reflog(git_repository *repo, const char *name);
-
-static int should_write_reflog(int *write, git_repository *repo, const char *name)
+static int packed_delete(refdb_fs_backend *backend, const char *ref_name)
{
- int error, logall;
+ size_t pack_pos;
+ int error, found = 0;
- error = git_repository__cvar(&logall, repo, GIT_CVAR_LOGALLREFUPDATES);
- if (error < 0)
- return error;
+ if ((error = packed_reload(backend)) < 0)
+ goto cleanup;
- /* Defaults to the opposite of the repo being bare */
- if (logall == GIT_LOGALLREFUPDATES_UNSET)
- logall = !git_repository_is_bare(repo);
+ if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
+ goto cleanup;
- *write = 0;
- switch (logall) {
- case GIT_LOGALLREFUPDATES_FALSE:
- *write = 0;
- break;
+ /* If a packed reference exists, remove it from the packfile and repack if necessary */
+ error = git_sortedcache_lookup_index(&pack_pos, backend->refcache, ref_name);
+ if (error == 0) {
+ error = git_sortedcache_remove(backend->refcache, pack_pos);
+ found = 1;
+ }
+ if (error == GIT_ENOTFOUND)
+ error = 0;
- case GIT_LOGALLREFUPDATES_TRUE:
- /* Only write if it already has a log,
- * or if it's under heads/, remotes/ or notes/
- */
- *write = has_reflog(repo, name) ||
- !git__prefixcmp(name, GIT_REFS_HEADS_DIR) ||
- !git__strcmp(name, GIT_HEAD_FILE) ||
- !git__prefixcmp(name, GIT_REFS_REMOTES_DIR) ||
- !git__prefixcmp(name, GIT_REFS_NOTES_DIR);
- break;
+ git_sortedcache_wunlock(backend->refcache);
- case GIT_LOGALLREFUPDATES_ALWAYS:
- *write = 1;
- break;
- }
+ if (found)
+ error = packed_write(backend);
- return 0;
+cleanup:
+ return error;
}
+static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *author, const char *message);
+
static int cmp_old_ref(int *cmp, git_refdb_backend *backend, const char *name,
const git_oid *old_id, const char *old_target)
{
*/
static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
{
- int error;
+ git_reference *head = NULL;
+ git_refdb *refdb = NULL;
+ int error, write_reflog;
git_oid old_id;
- git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
- const char *name;
- if (ref->type == GIT_REFERENCE_SYMBOLIC)
- return 0;
+ if ((error = git_repository_refdb(&refdb, backend->repo)) < 0 ||
+ (error = git_refdb_should_write_head_reflog(&write_reflog, refdb, ref)) < 0)
+ goto out;
+ if (!write_reflog)
+ goto out;
/* if we can't resolve, we use {0}*40 as old id */
if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
memset(&old_id, 0, sizeof(old_id));
- if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
- return error;
-
- if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
- goto cleanup;
-
- if ((error = git_reference_lookup(&tmp, backend->repo, GIT_HEAD_FILE)) < 0)
- goto cleanup;
-
- /* Go down the symref chain until we find the branch */
- while (git_reference_type(tmp) == GIT_REFERENCE_SYMBOLIC) {
- error = git_reference_lookup(&peeled, backend->repo, git_reference_symbolic_target(tmp));
- if (error < 0)
- break;
-
- git_reference_free(tmp);
- tmp = peeled;
- }
-
- if (error == GIT_ENOTFOUND) {
- error = 0;
- name = git_reference_symbolic_target(tmp);
- } else if (error < 0) {
- goto cleanup;
- } else {
- name = git_reference_name(tmp);
- }
-
- if (strcmp(name, ref->name))
- goto cleanup;
-
- error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message);
+ if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0 ||
+ (error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message)) < 0)
+ goto out;
-cleanup:
- git_reference_free(tmp);
+out:
git_reference_free(head);
+ git_refdb_free(refdb);
return error;
}
const git_oid *old_id,
const char *old_target)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
git_filebuf file = GIT_FILEBUF_INIT;
int error = 0;
if ((error = loose_lock(&file, backend, ref->name)) < 0)
return error;
- return refdb_fs_backend__write_tail(_backend, ref, &file, true, who, message, old_id, old_target);
+ return refdb_fs_backend__write_tail(_backend, ref, &file, true, old_id, old_target, who, message);
}
static int refdb_fs_backend__write_tail(
const git_reference *ref,
git_filebuf *file,
int update_reflog,
- const git_signature *who,
- const char *message,
const git_oid *old_id,
- const char *old_target)
+ const char *old_target,
+ const git_signature *who,
+ const char *message)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
int error = 0, cmp = 0, should_write;
const char *new_target = NULL;
const git_oid *new_id = NULL;
}
if (update_reflog) {
- if ((error = should_write_reflog(&should_write, backend->repo, ref->name)) < 0)
+ git_refdb *refdb;
+
+ if ((error = git_repository_refdb__weakptr(&refdb, backend->repo)) < 0 ||
+ (error = git_refdb_should_write_reflog(&should_write, refdb, ref)) < 0)
goto on_error;
if (should_write) {
return error;
}
-static void refdb_fs_backend__try_delete_empty_ref_hierarchie(
+static void refdb_fs_backend__prune_refs(
refdb_fs_backend *backend,
const char *ref_name,
- bool reflog)
+ const char *prefix)
{
git_buf relative_path = GIT_BUF_INIT;
git_buf base_path = GIT_BUF_INIT;
git_buf_truncate(&relative_path, commonlen);
- if (reflog) {
- if (git_buf_join3(&base_path, '/', backend->commonpath, GIT_REFLOG_DIR, git_buf_cstr(&relative_path)) < 0)
+ if (prefix) {
+ if (git_buf_join3(&base_path, '/', backend->commonpath, prefix, git_buf_cstr(&relative_path)) < 0)
goto cleanup;
} else {
if (git_buf_joinpath(&base_path, backend->commonpath, git_buf_cstr(&relative_path)) < 0)
const char *ref_name,
const git_oid *old_id, const char *old_target)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
git_filebuf file = GIT_FILEBUF_INIT;
int error = 0;
return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target);
}
+static int loose_delete(refdb_fs_backend *backend, const char *ref_name)
+{
+ git_buf loose_path = GIT_BUF_INIT;
+ int error = 0;
+
+ if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0)
+ return -1;
+
+ error = p_unlink(loose_path.ptr);
+ if (error < 0 && errno == ENOENT)
+ error = GIT_ENOTFOUND;
+ else if (error != 0)
+ error = -1;
+
+ git_buf_dispose(&loose_path);
+
+ return error;
+}
+
static int refdb_fs_backend__delete_tail(
git_refdb_backend *_backend,
git_filebuf *file,
const char *ref_name,
const git_oid *old_id, const char *old_target)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
- git_buf loose_path = GIT_BUF_INIT;
- size_t pack_pos;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
int error = 0, cmp = 0;
- bool loose_deleted = 0;
+ bool packed_deleted = 0;
error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target);
if (error < 0)
goto cleanup;
}
- /* If a loose reference exists, remove it from the filesystem */
- if (git_buf_joinpath(&loose_path, backend->commonpath, ref_name) < 0)
- return -1;
-
-
- error = p_unlink(loose_path.ptr);
- if (error < 0 && errno == ENOENT)
- error = 0;
- else if (error < 0)
+ /*
+ * To ensure that an external observer will see either the current ref value
+ * (because the loose ref still exists), or a missing ref (after the packed-file is
+ * unlocked, there will be nothing left), we must ensure things happen in the
+ * following order:
+ *
+ * - the packed-ref file is locked and loaded, as well as a loose one, if it exists
+ * - we optimistically delete a packed ref, keeping track of whether it existed
+ * - we delete the loose ref, note that we have its .lock
+ * - the loose ref is "unlocked", then the packed-ref file is rewritten and unlocked
+ * - we should prune the path components if a loose ref was deleted
+ *
+ * Note that, because our packed backend doesn't expose its filesystem lock,
+ * we might not be able to guarantee that this is what actually happens (ie.
+ * as our current code never write packed-refs.lock, nothing stops observers
+ * from grabbing a "stale" value from there).
+ */
+ if ((error = packed_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND)
goto cleanup;
- else if (error == 0)
- loose_deleted = 1;
- if ((error = packed_reload(backend)) < 0)
- goto cleanup;
+ if (error == 0)
+ packed_deleted = 1;
- /* If a packed reference exists, remove it from the packfile and repack */
- if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
+ if ((error = loose_delete(backend, ref_name)) < 0 && error != GIT_ENOTFOUND)
goto cleanup;
- if (!(error = git_sortedcache_lookup_index(
- &pack_pos, backend->refcache, ref_name)))
- error = git_sortedcache_remove(backend->refcache, pack_pos);
-
- git_sortedcache_wunlock(backend->refcache);
-
if (error == GIT_ENOTFOUND) {
- error = loose_deleted ? 0 : ref_error_notfound(ref_name);
+ error = packed_deleted ? 0 : ref_error_notfound(ref_name);
goto cleanup;
}
- error = packed_write(backend);
-
cleanup:
- git_buf_dispose(&loose_path);
git_filebuf_cleanup(file);
- if (loose_deleted)
- refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, ref_name, false);
+ if (error == 0)
+ refdb_fs_backend__prune_refs(backend, ref_name, "");
return error;
}
const git_signature *who,
const char *message)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
- git_reference *old, *new;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
+ git_reference *old, *new = NULL;
git_filebuf file = GIT_FILEBUF_INIT;
int error;
return error;
}
- new = git_reference__set_name(old, new_name);
+ new = git_reference__realloc(&old, new_name);
if (!new) {
git_reference_free(old);
return -1;
static int refdb_fs_backend__compress(git_refdb_backend *_backend)
{
int error;
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
assert(backend);
static void refdb_fs_backend__free(git_refdb_backend *_backend)
{
- refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
assert(backend);
static int reflog_parse(git_reflog *log, const char *buf, size_t buf_size)
{
- const char *ptr;
- git_reflog_entry *entry;
-
-#define seek_forward(_increase) do { \
- if (_increase >= buf_size) { \
- git_error_set(GIT_ERROR_INVALID, "ran out of data while parsing reflog"); \
- goto fail; \
- } \
- buf += _increase; \
- buf_size -= _increase; \
- } while (0)
-
- while (buf_size > GIT_REFLOG_SIZE_MIN) {
- entry = git__calloc(1, sizeof(git_reflog_entry));
- GIT_ERROR_CHECK_ALLOC(entry);
+ git_parse_ctx parser = GIT_PARSE_CTX_INIT;
- entry->committer = git__calloc(1, sizeof(git_signature));
- GIT_ERROR_CHECK_ALLOC(entry->committer);
+ if ((git_parse_ctx_init(&parser, buf, buf_size)) < 0)
+ return -1;
- if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < 0)
- goto fail;
- seek_forward(GIT_OID_HEXSZ + 1);
+ for (; parser.remain_len; git_parse_advance_line(&parser)) {
+ git_reflog_entry *entry;
+ const char *sig;
+ char c;
- if (git_oid_fromstrn(&entry->oid_cur, buf, GIT_OID_HEXSZ) < 0)
- goto fail;
- seek_forward(GIT_OID_HEXSZ + 1);
+ entry = git__calloc(1, sizeof(*entry));
+ GIT_ERROR_CHECK_ALLOC(entry);
+ entry->committer = git__calloc(1, sizeof(*entry->committer));
+ GIT_ERROR_CHECK_ALLOC(entry->committer);
- ptr = buf;
+ if (git_parse_advance_oid(&entry->oid_old, &parser) < 0 ||
+ git_parse_advance_expected(&parser, " ", 1) < 0 ||
+ git_parse_advance_oid(&entry->oid_cur, &parser) < 0)
+ goto next;
- /* Seek forward to the end of the signature. */
- while (*buf && *buf != '\t' && *buf != '\n')
- seek_forward(1);
+ sig = parser.line;
+ while (git_parse_peek(&c, &parser, 0) == 0 && c != '\t' && c != '\n')
+ git_parse_advance_chars(&parser, 1);
- if (git_signature__parse(entry->committer, &ptr, buf + 1, NULL, *buf) < 0)
- goto fail;
+ if (git_signature__parse(entry->committer, &sig, parser.line, NULL, 0) < 0)
+ goto next;
- if (*buf == '\t') {
- /* We got a message. Read everything till we reach LF. */
- seek_forward(1);
- ptr = buf;
+ if (c == '\t') {
+ size_t len;
+ git_parse_advance_chars(&parser, 1);
- while (*buf && *buf != '\n')
- seek_forward(1);
+ len = parser.line_len;
+ if (parser.line[len - 1] == '\n')
+ len--;
- entry->msg = git__strndup(ptr, buf - ptr);
+ entry->msg = git__strndup(parser.line, len);
GIT_ERROR_CHECK_ALLOC(entry->msg);
- } else
- entry->msg = NULL;
+ }
- while (*buf && *buf == '\n' && buf_size > 1)
- seek_forward(1);
+ if ((git_vector_insert(&log->entries, entry)) < 0) {
+ git_reflog_entry__free(entry);
+ return -1;
+ }
- if (git_vector_insert(&log->entries, entry) < 0)
- goto fail;
+ continue;
+
+next:
+ git_reflog_entry__free(entry);
}
return 0;
-
-#undef seek_forward
-
-fail:
- git_reflog_entry__free(entry);
-
- return -1;
}
static int create_new_reflog_file(const char *filepath)
assert(_backend && name);
- backend = (refdb_fs_backend *) _backend;
+ backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
repo = backend->repo;
if ((error = retrieve_reflog_path(&path, repo, name)) < 0)
assert(_backend && name);
- backend = (refdb_fs_backend *) _backend;
+ backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
return has_reflog(backend->repo, name);
}
assert(out && _backend && name);
- backend = (refdb_fs_backend *) _backend;
+ backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
repo = backend->repo;
if (reflog_alloc(&log, name) < 0)
git_buf_rtrim(buf);
if (msg) {
+ size_t i;
+
git_buf_putc(buf, '\t');
git_buf_puts(buf, msg);
+
+ for (i = 0; i < buf->size - 2; i++)
+ if (buf->ptr[i] == '\n')
+ buf->ptr[i] = ' ';
+ git_buf_rtrim(buf);
}
git_buf_putc(buf, '\n');
assert(_backend && reflog);
- backend = (refdb_fs_backend *) _backend;
+ backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
if ((error = lock_reflog(&fbuf, backend, reflog->ref_name)) < 0)
return -1;
!(old && new))
return 0;
- /* From here on is_symoblic also means that it's HEAD */
+ /* From here on is_symbolic also means that it's HEAD */
if (old) {
git_oid_cpy(&old_id, old);
assert(_backend && old_name && new_name);
- backend = (refdb_fs_backend *) _backend;
+ backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
repo = backend->repo;
if ((error = git_reference__normalize_name(
static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name)
{
- refdb_fs_backend *backend = (refdb_fs_backend *) _backend;
+ refdb_fs_backend *backend = GIT_CONTAINER_OF(_backend, refdb_fs_backend, parent);
git_buf path = GIT_BUF_INIT;
int error;
if ((error = p_unlink(path.ptr)) < 0)
goto out;
- refdb_fs_backend__try_delete_empty_ref_hierarchie(backend, name, true);
+ refdb_fs_backend__prune_refs(backend, name, GIT_REFLOG_DIR);
out:
git_buf_dispose(&path);
backend = git__calloc(1, sizeof(refdb_fs_backend));
GIT_ERROR_CHECK_ALLOC(backend);
+ if (git_refdb_init_backend(&backend->parent, GIT_REFDB_BACKEND_VERSION) < 0)
+ goto fail;
+
backend->repo = repository;
if (repository->gitdir) {
git_buf_dispose(&gitpath);
- if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_IGNORECASE) && t) {
+ if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_IGNORECASE) && t) {
backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE;
backend->direach_flags |= GIT_PATH_DIR_IGNORE_CASE;
}
- if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_PRECOMPOSE) && t) {
+ if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_PRECOMPOSE) && t) {
backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE;
}
- if ((!git_repository__cvar(&t, backend->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) ||
+ if ((!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) ||
git_repository__fsync_gitdir)
backend->fsync = 1;
backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS;
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_refdb_fs_h__
-#define INCLUDE_refdb_fs_h__
-
-#include "common.h"
-
-#include "strmap.h"
-
-typedef struct {
- git_strmap *packfile;
- time_t packfile_time;
-} git_refcache;
-
-#endif
#include "signature.h"
#include "refdb.h"
-#include <git2/sys/refdb_backend.h>
-
-git_reflog_entry *git_reflog_entry__alloc(void)
-{
- return git__calloc(1, sizeof(git_reflog_entry));
-}
+#include "git2/sys/refdb_backend.h"
+#include "git2/sys/reflog.h"
void git_reflog_entry__free(git_reflog_entry *entry)
{
int git_reflog_append(git_reflog *reflog, const git_oid *new_oid, const git_signature *committer, const char *msg)
{
- git_reflog_entry *entry;
const git_reflog_entry *previous;
- const char *newline;
+ git_reflog_entry *entry;
assert(reflog && new_oid && committer);
goto cleanup;
if (msg != NULL) {
- if ((entry->msg = git__strdup(msg)) == NULL)
- goto cleanup;
+ size_t i, msglen = strlen(msg);
- newline = strchr(msg, '\n');
-
- if (newline) {
- if (newline[1] != '\0') {
- git_error_set(GIT_ERROR_INVALID, "reflog message cannot contain newline");
- goto cleanup;
- }
+ if ((entry->msg = git__strndup(msg, msglen)) == NULL)
+ goto cleanup;
- entry->msg[newline - msg] = '\0';
- }
+ /*
+ * Replace all newlines with spaces, except for
+ * the final trailing newline.
+ */
+ for (i = 0; i < msglen; i++)
+ if (entry->msg[i] == '\n')
+ entry->msg[i] = ' ';
}
previous = git_reflog_entry_byindex(reflog, 0);
#include "hash.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "filebuf.h"
#include "pack.h"
#include "reflog.h"
bool git_reference__enable_symbolic_ref_target_validation = true;
-#define DEFAULT_NESTING_LEVEL 5
-#define MAX_NESTING_LEVEL 10
-
enum {
GIT_PACKREF_HAS_PEEL = 1,
GIT_PACKREF_WAS_LOOSE = 2
return ref;
}
-git_reference *git_reference__set_name(
- git_reference *ref, const char *name)
+git_reference *git_reference__realloc(
+ git_reference **ptr_to_ref, const char *name)
{
- size_t namelen = strlen(name);
- size_t reflen;
+ size_t namelen, reflen;
git_reference *rewrite = NULL;
+ assert(ptr_to_ref && name);
+
+ namelen = strlen(name);
+
if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
!GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
- (rewrite = git__realloc(ref, reflen)) != NULL)
+ (rewrite = git__realloc(*ptr_to_ref, reflen)) != NULL)
memcpy(rewrite->name, name, namelen + 1);
+ *ptr_to_ref = NULL;
+
return rewrite;
}
const git_oid *old_id = NULL;
const char *old_target = NULL;
+ if (!strcmp(ref->name, "HEAD")) {
+ git_error_set(GIT_ERROR_REFERENCE, "cannot delete HEAD");
+ return GIT_ERROR;
+ }
+
if (ref->type == GIT_REFERENCE_DIRECT)
old_id = &ref->target.oid;
else
int precompose;
unsigned int flags = GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL;
- if (!git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) &&
+ if (!git_repository__configmap_lookup(&precompose, repo, GIT_CONFIGMAP_PRECOMPOSE) &&
precompose)
flags |= GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE;
const char *name,
int max_nesting)
{
- git_refname_t scan_name;
- git_reference_t scan_type;
- int error = 0, nesting;
- git_reference *ref = NULL;
+ git_refname_t normalized;
git_refdb *refdb;
+ int error = 0;
assert(ref_out && repo && name);
- *ref_out = NULL;
-
- if (max_nesting > MAX_NESTING_LEVEL)
- max_nesting = MAX_NESTING_LEVEL;
- else if (max_nesting < 0)
- max_nesting = DEFAULT_NESTING_LEVEL;
-
- scan_type = GIT_REFERENCE_SYMBOLIC;
-
- if ((error = reference_normalize_for_repo(scan_name, repo, name, true)) < 0)
- return error;
-
- if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
+ if ((error = reference_normalize_for_repo(normalized, repo, name, true)) < 0 ||
+ (error = git_repository_refdb__weakptr(&refdb, repo)) < 0 ||
+ (error = git_refdb_resolve(ref_out, refdb, normalized, max_nesting)) < 0)
return error;
- for (nesting = max_nesting;
- nesting >= 0 && scan_type == GIT_REFERENCE_SYMBOLIC;
- nesting--)
- {
- if (nesting != max_nesting) {
- strncpy(scan_name, ref->target.symbolic, sizeof(scan_name));
- git_reference_free(ref);
- }
-
- if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0)
- return error;
-
- scan_type = ref->type;
- }
-
- if (scan_type != GIT_REFERENCE_DIRECT && max_nesting != 0) {
- git_error_set(GIT_ERROR_REFERENCE,
- "cannot resolve reference (>%u levels deep)", max_nesting);
- git_reference_free(ref);
- return -1;
+ /*
+ * The resolved reference may be a symbolic reference in case its
+ * target doesn't exist. If the user asked us to resolve (e.g.
+ * `max_nesting != 0`), then we need to return an error in case we got
+ * a symbolic reference back.
+ */
+ if (max_nesting && git_reference_type(*ref_out) == GIT_REFERENCE_SYMBOLIC) {
+ git_reference_free(*ref_out);
+ *ref_out = NULL;
+ return GIT_ENOTFOUND;
}
- *ref_out = ref;
return 0;
}
-int git_reference__read_head(
- git_reference **out,
- git_repository *repo,
- const char *path)
-{
- git_buf reference = GIT_BUF_INIT;
- char *name = NULL;
- int error;
-
- if ((error = git_futils_readbuffer(&reference, path)) < 0)
- goto out;
- git_buf_rtrim(&reference);
-
- if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) {
- git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
-
- name = git_path_basename(path);
-
- if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) {
- error = -1;
- goto out;
- }
- } else {
- if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0)
- goto out;
- }
-
-out:
- git__free(name);
- git_buf_dispose(&reference);
-
- return error;
-}
-
int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
{
int error = 0, i;
{
assert(ref);
- if (ref->type != GIT_REFERENCE_DIRECT || git_oid_iszero(&ref->peel))
+ if (ref->type != GIT_REFERENCE_DIRECT || git_oid_is_zero(&ref->peel))
return NULL;
return &ref->peel;
return 0;
}
-int configured_ident(git_signature **out, const git_repository *repo)
+static int refs_configured_ident(git_signature **out, const git_repository *repo)
{
if (repo->ident_name && repo->ident_email)
return git_signature_now(out, repo->ident_name, repo->ident_email);
int error;
git_signature *who;
- if(((error = configured_ident(&who, repo)) < 0) &&
+ if(((error = refs_configured_ident(&who, repo)) < 0) &&
((error = git_signature_default(&who, repo)) < 0) &&
((error = git_signature_now(&who, "unknown", "unknown")) < 0))
return error;
typedef struct {
const char *old_name;
git_refname_t new_name;
-} rename_cb_data;
+} refs_update_head_payload;
-static int update_wt_heads(git_repository *repo, const char *path, void *payload)
+static int refs_update_head(git_repository *worktree, void *_payload)
{
- rename_cb_data *data = (rename_cb_data *) payload;
- git_reference *head = NULL;
- char *gitdir = NULL;
+ refs_update_head_payload *payload = (refs_update_head_payload *)_payload;
+ git_reference *head = NULL, *updated = NULL;
int error;
- if ((error = git_reference__read_head(&head, repo, path)) < 0) {
- git_error_set(GIT_ERROR_REFERENCE, "could not read HEAD when renaming references");
+ if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0)
goto out;
- }
-
- if ((gitdir = git_path_dirname(path)) == NULL) {
- error = -1;
- goto out;
- }
if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC ||
- git__strcmp(head->target.symbolic, data->old_name) != 0) {
- error = 0;
+ git__strcmp(git_reference_symbolic_target(head), payload->old_name) != 0)
goto out;
- }
- /* Update HEAD it was pointing to the reference being renamed */
- if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) {
+ /* Update HEAD if it was pointing to the reference being renamed */
+ if ((error = git_reference_symbolic_set_target(&updated, head, payload->new_name, NULL)) < 0) {
git_error_set(GIT_ERROR_REFERENCE, "failed to update HEAD after renaming reference");
goto out;
}
out:
+ git_reference_free(updated);
git_reference_free(head);
- git__free(gitdir);
-
return error;
}
-static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
- const git_signature *signature, const char *message)
-{
- git_repository *repo;
- git_refname_t normalized;
- bool should_head_be_updated = false;
- int error = 0;
-
- assert(ref && new_name && signature);
-
- repo = git_reference_owner(ref);
-
- if ((error = reference_normalize_for_repo(
- normalized, repo, new_name, true)) < 0)
- return error;
-
- /* Check if we have to update HEAD. */
- if ((error = git_branch_is_head(ref)) < 0)
- return error;
-
- should_head_be_updated = (error > 0);
-
- if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
- return error;
-
- /* Update HEAD if it was pointing to the reference being renamed */
- if (should_head_be_updated) {
- error = git_repository_set_head(ref->db->repo, normalized);
- } else {
- rename_cb_data payload;
- payload.old_name = ref->name;
- memcpy(&payload.new_name, &normalized, sizeof(normalized));
-
- error = git_repository_foreach_head(repo, update_wt_heads, &payload);
- }
-
- return error;
-}
-
-
int git_reference_rename(
git_reference **out,
git_reference *ref,
int force,
const char *log_message)
{
- git_signature *who;
+ refs_update_head_payload payload;
+ git_signature *signature = NULL;
+ git_repository *repo;
int error;
assert(out && ref);
- if ((error = git_reference__log_signature(&who, ref->db->repo)) < 0)
- return error;
+ repo = git_reference_owner(ref);
- error = reference__rename(out, ref, new_name, force, who, log_message);
- git_signature_free(who);
+ if ((error = git_reference__log_signature(&signature, repo)) < 0 ||
+ (error = reference_normalize_for_repo(payload.new_name, repo, new_name, true)) < 0 ||
+ (error = git_refdb_rename(out, ref->db, ref->name, payload.new_name, force, signature, log_message)) < 0)
+ goto out;
+
+ payload.old_name = ref->name;
+
+ /* We may have to update any HEAD that was pointing to the renamed reference. */
+ if ((error = git_repository_foreach_worktree(repo, refs_update_head, &payload)) < 0)
+ goto out;
+out:
+ git_signature_free(signature);
return error;
}
case '\\':
case '?':
case '[':
- case '*':
return 0;
default:
return 1;
}
}
-static int ensure_segment_validity(const char *name)
+static int ensure_segment_validity(const char *name, char may_contain_glob)
{
const char *current = name;
char prev = '\0';
if (prev == '@' && *current == '{')
return -1; /* Refname contains "@{" */
+ if (*current == '*') {
+ if (!may_contain_glob)
+ return -1;
+ may_contain_glob = 0;
+ }
+
prev = *current;
}
}
while (true) {
- segment_len = ensure_segment_validity(current);
- if (segment_len < 0) {
- if ((process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) &&
- current[0] == '*' &&
- (current[1] == '\0' || current[1] == '/')) {
- /* Accept one wildcard as a full refname component. */
- process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
- segment_len = 1;
- } else
- goto cleanup;
- }
+ char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
+
+ segment_len = ensure_segment_validity(current, may_contain_glob);
+ if (segment_len < 0)
+ goto cleanup;
if (segment_len > 0) {
+ /*
+ * There may only be one glob in a pattern, thus we reset
+ * the pattern-flag in case the current segment has one.
+ */
+ if (memchr(current, '*', segment_len))
+ process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
+
if (normalize) {
size_t cur_len = git_buf_len(buf);
return git_oid__cmp(&ref1->target.oid, &ref2->target.oid);
}
-/**
- * Get the end of a chain of references. If the final one is not
- * found, we return the reference just before that.
- */
-static int get_terminal(git_reference **out, git_repository *repo, const char *ref_name, int nesting)
-{
- git_reference *ref;
- int error = 0;
-
- if (nesting > MAX_NESTING_LEVEL) {
- git_error_set(GIT_ERROR_REFERENCE, "reference chain too deep (%d)", nesting);
- return GIT_ENOTFOUND;
- }
-
- /* set to NULL to let the caller know that they're at the end of the chain */
- if ((error = git_reference_lookup(&ref, repo, ref_name)) < 0) {
- *out = NULL;
- return error;
- }
-
- if (git_reference_type(ref) == GIT_REFERENCE_DIRECT) {
- *out = ref;
- error = 0;
- } else {
- error = get_terminal(out, repo, git_reference_symbolic_target(ref), nesting + 1);
- if (error == GIT_ENOTFOUND && !*out)
- *out = ref;
- else
- git_reference_free(ref);
- }
-
- return error;
-}
-
/*
* Starting with the reference given by `ref_name`, follows symbolic
* references until a direct reference is found and updated the OID
{
git_reference *ref = NULL, *ref2 = NULL;
git_signature *who = NULL;
+ git_refdb *refdb = NULL;
const git_signature *to_use;
int error = 0;
if (!sig && (error = git_reference__log_signature(&who, repo)) < 0)
- return error;
+ goto out;
to_use = sig ? sig : who;
- error = get_terminal(&ref, repo, ref_name, 0);
- /* found a dangling symref */
- if (error == GIT_ENOTFOUND && ref) {
- assert(git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC);
- git_error_clear();
+ if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0)
+ goto out;
+
+ if ((error = git_refdb_resolve(&ref, refdb, ref_name, -1)) < 0) {
+ if (error == GIT_ENOTFOUND) {
+ git_error_clear();
+ error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use,
+ log_message, NULL, NULL);
+ }
+ goto out;
+ }
+
+ /* In case the resolved reference is symbolic, then it's a dangling symref. */
+ if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
error = reference__create(&ref2, repo, ref->target.symbolic, oid, NULL, 0, to_use,
log_message, NULL, NULL);
- } else if (error == GIT_ENOTFOUND) {
- git_error_clear();
- error = reference__create(&ref2, repo, ref_name, oid, NULL, 0, to_use,
- log_message, NULL, NULL);
- } else if (error == 0) {
- assert(git_reference_type(ref) == GIT_REFERENCE_DIRECT);
+ } else {
error = reference__create(&ref2, repo, ref->name, oid, NULL, 1, to_use,
log_message, &ref->target.oid, NULL);
}
+out:
git_reference_free(ref2);
git_reference_free(ref);
git_signature_free(who);
* to a commit. So we only want to use the peeled value
* if it is not zero and the target is not a tag.
*/
- if (target_type != GIT_OBJECT_TAG && !git_oid_iszero(&resolved->peel)) {
+ if (target_type != GIT_OBJECT_TAG && !git_oid_is_zero(&resolved->peel)) {
error = git_object_lookup(&target,
git_reference_owner(ref), &resolved->peel, GIT_OBJECT_ANY);
} else {
#define GIT_REBASE_APPLY_DIR "rebase-apply/"
#define GIT_REBASE_APPLY_REBASING_FILE GIT_REBASE_APPLY_DIR "rebasing"
#define GIT_REBASE_APPLY_APPLYING_FILE GIT_REBASE_APPLY_DIR "applying"
-#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
#define GIT_SEQUENCER_DIR "sequencer/"
#define GIT_SEQUENCER_HEAD_FILE GIT_SEQUENCER_DIR "head"
char name[GIT_FLEX_ARRAY];
};
-git_reference *git_reference__set_name(git_reference *ref, const char *name);
+/**
+ * Reallocate the reference with a new name
+ *
+ * Note that this is a dangerous operation, as on success, all existing
+ * pointers to the old reference will now be dangling. Only call this on objects
+ * you control, possibly using `git_reference_dup`.
+ */
+git_reference *git_reference__realloc(git_reference **ptr_to_ref, const char *name);
int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags);
int git_reference__update_terminal(git_repository *repo, const char *ref_name, const git_oid *oid, const git_signature *sig, const char *log_message);
int git_reference__is_branch(const char *ref_name);
int git_reference__is_remote(const char *ref_name);
int git_reference__is_tag(const char *ref_name);
+int git_reference__is_note(const char *ref_name);
const char *git_reference__shorthand(const char *name);
/**
const char *name,
int max_deref);
-/**
- * Read reference from a file.
- *
- * This function will read in the file at `path`. If it is a
- * symref, it will return a new unresolved symbolic reference
- * with the given name pointing to the reference pointed to by
- * the file. If it is not a symbolic reference, it will return
- * the resolved reference.
- *
- * Note that because the refdb is not involved for symbolic references, they
- * won't be owned, hence you should either not make the returned reference
- * 'externally visible', or perform the lookup before returning it to the user.
- */
-int git_reference__read_head(
- git_reference **out,
- git_repository *repo,
- const char *path);
-
int git_reference__log_signature(git_signature **out, git_repository *repo);
/** Update a reference after a commit. */
#include "git2/errors.h"
-#include "util.h"
-#include "posix.h"
#include "refs.h"
+#include "util.h"
#include "vector.h"
+#include "wildmatch.h"
int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
{
if (refspec == NULL || refspec->src == NULL)
return false;
- return (p_fnmatch(refspec->src, refname, 0) == 0);
+ return (wildmatch(refspec->src, refname, 0) == 0);
}
int git_refspec_dst_matches(const git_refspec *refspec, const char *refname)
if (refspec == NULL || refspec->dst == NULL)
return false;
- return (p_fnmatch(refspec->dst, refname, 0) == 0);
+ return (wildmatch(refspec->dst, refname, 0) == 0);
}
static int refspec_transform(
git_buf *out, const char *from, const char *to, const char *name)
{
const char *from_star, *to_star;
- const char *name_slash, *from_slash;
size_t replacement_len, star_offset;
git_buf_sanitize(out);
/* the first half is copied over */
git_buf_put(out, to, to_star - to);
- /* then we copy over the replacement, from the star's offset to the next slash in 'name' */
- name_slash = strchr(name + star_offset, '/');
- if (!name_slash)
- name_slash = strrchr(name, '\0');
-
- /* if there is no slash after the star in 'from', we want to copy everything over */
- from_slash = strchr(from + star_offset, '/');
- if (!from_slash)
- name_slash = strrchr(name, '\0');
-
- replacement_len = (name_slash - name) - star_offset;
+ /*
+ * Copy over the name, but exclude the trailing part in "from" starting
+ * after the glob
+ */
+ replacement_len = strlen(name + star_offset) - strlen(from_star + 1);
git_buf_put(out, name + star_offset, replacement_len);
return git_buf_puts(out, to_star + 1);
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "regexp.h"
+
+#if defined(GIT_REGEX_BUILTIN) || defined(GIT_REGEX_PCRE)
+
+int git_regexp_compile(git_regexp *r, const char *pattern, int flags)
+{
+ int erroffset, cflags = 0;
+ const char *error = NULL;
+
+ if (flags & GIT_REGEXP_ICASE)
+ cflags |= PCRE_CASELESS;
+
+ if ((*r = pcre_compile(pattern, cflags, &error, &erroffset, NULL)) == NULL) {
+ git_error_set_str(GIT_ERROR_REGEX, error);
+ return GIT_EINVALIDSPEC;
+ }
+
+ return 0;
+}
+
+void git_regexp_dispose(git_regexp *r)
+{
+ pcre_free(*r);
+ *r = NULL;
+}
+
+int git_regexp_match(const git_regexp *r, const char *string)
+{
+ int error;
+ if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, NULL, 0)) < 0)
+ return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
+ return 0;
+}
+
+int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches)
+{
+ int static_ovec[9] = {0}, *ovec;
+ int error;
+ size_t i;
+
+ /* The ovec array always needs to be a mutiple of three */
+ if (nmatches <= ARRAY_SIZE(static_ovec) / 3)
+ ovec = static_ovec;
+ else
+ ovec = git__calloc(nmatches * 3, sizeof(*ovec));
+ GIT_ERROR_CHECK_ALLOC(ovec);
+
+ if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, ovec, (int) nmatches * 3)) < 0)
+ goto out;
+
+ if (error == 0)
+ error = (int) nmatches;
+
+ for (i = 0; i < (unsigned int) error; i++) {
+ matches[i].start = (ovec[i * 2] < 0) ? -1 : ovec[i * 2];
+ matches[i].end = (ovec[i * 2 + 1] < 0) ? -1 : ovec[i * 2 + 1];
+ }
+ for (i = (unsigned int) error; i < nmatches; i++)
+ matches[i].start = matches[i].end = -1;
+
+out:
+ if (nmatches > ARRAY_SIZE(static_ovec) / 3)
+ git__free(ovec);
+ if (error < 0)
+ return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
+ return 0;
+}
+
+#elif defined(GIT_REGEX_PCRE2)
+
+int git_regexp_compile(git_regexp *r, const char *pattern, int flags)
+{
+ unsigned char errmsg[1024];
+ PCRE2_SIZE erroff;
+ int error, cflags = 0;
+
+ if (flags & GIT_REGEXP_ICASE)
+ cflags |= PCRE2_CASELESS;
+
+ if ((*r = pcre2_compile((const unsigned char *) pattern, PCRE2_ZERO_TERMINATED,
+ cflags, &error, &erroff, NULL)) == NULL) {
+ pcre2_get_error_message(error, errmsg, sizeof(errmsg));
+ git_error_set_str(GIT_ERROR_REGEX, (char *) errmsg);
+ return GIT_EINVALIDSPEC;
+ }
+
+ return 0;
+}
+
+void git_regexp_dispose(git_regexp *r)
+{
+ pcre2_code_free(*r);
+ *r = NULL;
+}
+
+int git_regexp_match(const git_regexp *r, const char *string)
+{
+ pcre2_match_data *data;
+ int error;
+
+ data = pcre2_match_data_create(1, NULL);
+ GIT_ERROR_CHECK_ALLOC(data);
+
+ if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string),
+ 0, 0, data, NULL)) < 0)
+ return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
+
+ pcre2_match_data_free(data);
+ return 0;
+}
+
+int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches)
+{
+ pcre2_match_data *data = NULL;
+ PCRE2_SIZE *ovec;
+ int error;
+ size_t i;
+
+ if ((data = pcre2_match_data_create(nmatches, NULL)) == NULL) {
+ git_error_set_oom();
+ goto out;
+ }
+
+ if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string),
+ 0, 0, data, NULL)) < 0)
+ goto out;
+
+ if (error == 0 || (unsigned int) error > nmatches)
+ error = nmatches;
+ ovec = pcre2_get_ovector_pointer(data);
+
+ for (i = 0; i < (unsigned int) error; i++) {
+ matches[i].start = (ovec[i * 2] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2];
+ matches[i].end = (ovec[i * 2 + 1] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2 + 1];
+ }
+ for (i = (unsigned int) error; i < nmatches; i++)
+ matches[i].start = matches[i].end = -1;
+
+out:
+ pcre2_match_data_free(data);
+ if (error < 0)
+ return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
+ return 0;
+}
+
+#elif defined(GIT_REGEX_REGCOMP) || defined(GIT_REGEX_REGCOMP_L)
+
+#if defined(GIT_REGEX_REGCOMP_L)
+# include <xlocale.h>
+#endif
+
+int git_regexp_compile(git_regexp *r, const char *pattern, int flags)
+{
+ int cflags = REG_EXTENDED, error;
+ char errmsg[1024];
+
+ if (flags & GIT_REGEXP_ICASE)
+ cflags |= REG_ICASE;
+
+# if defined(GIT_REGEX_REGCOMP)
+ if ((error = regcomp(r, pattern, cflags)) != 0)
+# else
+ if ((error = regcomp_l(r, pattern, cflags, (locale_t) 0)) != 0)
+# endif
+ {
+ regerror(error, r, errmsg, sizeof(errmsg));
+ git_error_set_str(GIT_ERROR_REGEX, errmsg);
+ return GIT_EINVALIDSPEC;
+ }
+
+ return 0;
+}
+
+void git_regexp_dispose(git_regexp *r)
+{
+ regfree(r);
+}
+
+int git_regexp_match(const git_regexp *r, const char *string)
+{
+ int error;
+ if ((error = regexec(r, string, 0, NULL, 0)) != 0)
+ return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
+ return 0;
+}
+
+int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches)
+{
+ regmatch_t static_m[3], *m;
+ int error;
+ size_t i;
+
+ if (nmatches <= ARRAY_SIZE(static_m))
+ m = static_m;
+ else
+ m = git__calloc(nmatches, sizeof(*m));
+
+ if ((error = regexec(r, string, nmatches, m, 0)) != 0)
+ goto out;
+
+ for (i = 0; i < nmatches; i++) {
+ matches[i].start = (m[i].rm_so < 0) ? -1 : m[i].rm_so;
+ matches[i].end = (m[i].rm_eo < 0) ? -1 : m[i].rm_eo;
+ }
+
+out:
+ if (nmatches > ARRAY_SIZE(static_m))
+ git__free(m);
+ if (error)
+ return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
+ return 0;
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_regexp_h__
+#define INCLUDE_regexp_h__
+
+#include "common.h"
+
+#if defined(GIT_REGEX_BUILTIN) || defined(GIT_REGEX_PCRE)
+# include "pcre.h"
+typedef pcre *git_regexp;
+# define GIT_REGEX_INIT NULL
+#elif defined(GIT_REGEX_PCRE2)
+# define PCRE2_CODE_UNIT_WIDTH 8
+# include <pcre2.h>
+typedef pcre2_code *git_regexp;
+# define GIT_REGEX_INIT NULL
+#elif defined(GIT_REGEX_REGCOMP) || defined(GIT_REGEX_REGCOMP_L)
+# include <regex.h>
+typedef regex_t git_regexp;
+# define GIT_REGEX_INIT { 0 }
+#else
+# error "No regex backend"
+#endif
+
+/** Options supported by @git_regexp_compile. */
+typedef enum {
+ /** Enable case-insensitive matching */
+ GIT_REGEXP_ICASE = (1 << 0)
+} git_regexp_flags_t;
+
+/** Structure containing information about regular expression matching groups */
+typedef struct {
+ /** Start of the given match. -1 if the group didn't match anything */
+ ssize_t start;
+ /** End of the given match. -1 if the group didn't match anything */
+ ssize_t end;
+} git_regmatch;
+
+/**
+ * Compile a regular expression. The compiled expression needs to
+ * be cleaned up afterwards with `git_regexp_dispose`.
+ *
+ * @param r Pointer to the storage where to initialize the regular expression.
+ * @param pattern The pattern that shall be compiled.
+ * @param flags Flags to alter how the pattern shall be handled.
+ * 0 for defaults, otherwise see @git_regexp_flags_t.
+ * @return 0 on success, otherwise a negative return value.
+ */
+int git_regexp_compile(git_regexp *r, const char *pattern, int flags);
+
+/**
+ * Free memory associated with the regular expression
+ *
+ * @param r The regular expression structure to dispose.
+ */
+void git_regexp_dispose(git_regexp *r);
+
+/**
+ * Test whether a given string matches a compiled regular
+ * expression.
+ *
+ * @param r Compiled regular expression.
+ * @param string String to match against the regular expression.
+ * @return 0 if the string matches, a negative error code
+ * otherwise. GIT_ENOTFOUND if no match was found,
+ * GIT_EINVALIDSPEC if the regular expression matching
+ * was invalid.
+ */
+int git_regexp_match(const git_regexp *r, const char *string);
+
+/**
+ * Search for matches inside of a given string.
+ *
+ * Given a regular expression with capturing groups, this
+ * function will populate provided @git_regmatch structures with
+ * offsets for each of the given matches. Non-matching groups
+ * will have start and end values of the respective @git_regmatch
+ * structure set to -1.
+ *
+ * @param r Compiled regular expression.
+ * @param string String to match against the regular expression.
+ * @param nmatches Number of @git_regmatch structures provided by
+ * the user.
+ * @param matches Pointer to an array of @git_regmatch structures.
+ * @return 0 if the string matches, a negative error code
+ * otherwise. GIT_ENOTFOUND if no match was found,
+ * GIT_EINVALIDSPEC if the regular expression matching
+ * was invalid.
+ */
+int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches);
+
+#endif
return 0;
}
-#if 0
-/* We could export this as a helper */
-static int get_check_cert(int *out, git_repository *repo)
-{
- git_config *cfg;
- const char *val;
- int error = 0;
-
- assert(out && repo);
-
- /* By default, we *DO* want to verify the certificate. */
- *out = 1;
-
- /* Go through the possible sources for SSL verification settings, from
- * most specific to least specific. */
-
- /* GIT_SSL_NO_VERIFY environment variable */
- if ((val = p_getenv("GIT_SSL_NO_VERIFY")) != NULL)
- return git_config_parse_bool(out, val);
-
- /* http.sslVerify config setting */
- if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
- return error;
-
- *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
- return 0;
-}
-#endif
-
static int canonicalize_url(git_buf *out, const char *in)
{
if (in == NULL || strlen(in) == 0) {
return GIT_EEXISTS;
}
-int git_remote_create_init_options(git_remote_create_options *opts, unsigned int version)
+int git_remote_create_options_init(git_remote_create_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_remote_create_options, GIT_REMOTE_CREATE_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_remote_create_init_options(git_remote_create_options *opts, unsigned int version)
+{
+ return git_remote_create_options_init(opts, version);
+}
+#endif
+
int git_remote_create_with_opts(git_remote **out, const char *url, const git_remote_create_options *opts)
{
git_remote *remote = NULL;
return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
}
-const char* git_remote__urlfordirection(git_remote *remote, int direction)
+static int resolve_url(git_buf *resolved_url, const char *url, int direction, const git_remote_callbacks *callbacks)
{
- assert(remote);
+ int status;
+
+ if (callbacks && callbacks->resolve_url) {
+ git_buf_clear(resolved_url);
+ status = callbacks->resolve_url(resolved_url, url, direction, callbacks->payload);
+ if (status != GIT_PASSTHROUGH) {
+ git_error_set_after_callback_function(status, "git_resolve_url_cb");
+ git_buf_sanitize(resolved_url);
+ return status;
+ }
+ }
+
+ return git_buf_sets(resolved_url, url);
+}
+int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks)
+{
+ const char *url = NULL;
+
+ assert(remote);
assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
if (direction == GIT_DIRECTION_FETCH) {
- return remote->url;
+ url = remote->url;
+ } else if (direction == GIT_DIRECTION_PUSH) {
+ url = remote->pushurl ? remote->pushurl : remote->url;
}
- if (direction == GIT_DIRECTION_PUSH) {
- return remote->pushurl ? remote->pushurl : remote->url;
+ if (!url) {
+ git_error_set(GIT_ERROR_INVALID,
+ "malformed remote '%s' - missing %s URL",
+ remote->name ? remote->name : "(anonymous)",
+ direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
+ return GIT_EINVALID;
}
-
- return NULL;
+ return resolve_url(url_out, url, direction, callbacks);
}
-int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
+static int remote_transport_set_callbacks(git_transport *t, const git_remote_callbacks *cbs)
{
if (!t->set_callbacks || !cbs)
return 0;
int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn)
{
git_transport *t;
- const char *url;
+ git_buf url = GIT_BUF_INIT;
int flags = GIT_TRANSPORTFLAGS_NONE;
int error;
void *payload = NULL;
- git_cred_acquire_cb credentials = NULL;
+ git_credential_acquire_cb credentials = NULL;
git_transport_cb transport = NULL;
assert(remote);
t = remote->transport;
- url = git_remote__urlfordirection(remote, direction);
- if (url == NULL) {
- git_error_set(GIT_ERROR_INVALID,
- "Malformed remote '%s' - missing %s URL",
- remote->name ? remote->name : "(anonymous)",
- direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
- return -1;
- }
+ if ((error = git_remote__urlfordirection(&url, remote, direction, callbacks)) < 0)
+ goto on_error;
/* If we don't have a transport object yet, and the caller specified a
* custom transport factory, use that */
if (!t && transport &&
(error = transport(&t, remote, payload)) < 0)
- return error;
+ goto on_error;
/* If we still don't have a transport, then use the global
* transport registrations which map URI schemes to transport factories */
- if (!t && (error = git_transport_new(&t, remote, url)) < 0)
- return error;
+ if (!t && (error = git_transport_new(&t, remote, url.ptr)) < 0)
+ goto on_error;
if ((error = set_transport_custom_headers(t, conn->custom_headers)) != 0)
goto on_error;
- if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
- (error = t->connect(t, url, credentials, payload, conn->proxy, direction, flags)) != 0)
+ if ((error = remote_transport_set_callbacks(t, callbacks)) < 0 ||
+ (error = t->connect(t, url.ptr, credentials, payload, conn->proxy, direction, flags)) != 0)
goto on_error;
remote->transport = t;
+ git_buf_dispose(&url);
+
return 0;
on_error:
- t->free(t);
+ if (t)
+ t->free(t);
+
+ git_buf_dispose(&url);
if (t == remote->transport)
remote->transport = NULL;
}
out:
- git_strarray_free(&arr);
+ git_strarray_dispose(&arr);
return error;
}
return remote->transport->is_connected(remote->transport);
}
-void git_remote_stop(git_remote *remote)
+int git_remote_stop(git_remote *remote)
{
assert(remote);
if (remote->transport && remote->transport->cancel)
remote->transport->cancel(remote->transport);
+
+ return 0;
}
-void git_remote_disconnect(git_remote *remote)
+int git_remote_disconnect(git_remote *remote)
{
assert(remote);
if (git_remote_connected(remote))
remote->transport->close(remote->transport);
+
+ return 0;
}
void git_remote_free(git_remote *remote)
return 0;
}
-const git_transfer_progress* git_remote_stats(git_remote *remote)
+const git_indexer_progress *git_remote_stats(git_remote *remote)
{
assert(remote);
return &remote->stats;
const git_remote_head *guess = NULL;
const git_oid *head_id;
size_t heads_len, i;
+ git_buf local_default = GIT_BUF_INIT;
int error;
assert(out);
if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
- return error;
-
- if (heads_len == 0)
- return GIT_ENOTFOUND;
+ goto done;
- if (strcmp(heads[0]->name, GIT_HEAD_FILE))
- return GIT_ENOTFOUND;
+ if (heads_len == 0 || strcmp(heads[0]->name, GIT_HEAD_FILE)) {
+ error = GIT_ENOTFOUND;
+ goto done;
+ }
git_buf_sanitize(out);
+
/* the first one must be HEAD so if that has the symref info, we're done */
- if (heads[0]->symref_target)
- return git_buf_puts(out, heads[0]->symref_target);
+ if (heads[0]->symref_target) {
+ error = git_buf_puts(out, heads[0]->symref_target);
+ goto done;
+ }
/*
* If there's no symref information, we have to look over them
- * and guess. We return the first match unless the master
- * branch is a candidate. Then we return the master branch.
+ * and guess. We return the first match unless the default
+ * branch is a candidate. Then we return the default branch.
*/
+
+ if ((error = git_repository_initialbranch(&local_default, remote->repo)) < 0)
+ goto done;
+
head_id = &heads[0]->oid;
for (i = 1; i < heads_len; i++) {
continue;
}
- if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
+ if (!git__strcmp(local_default.ptr, heads[i]->name)) {
guess = heads[i];
break;
}
}
- if (!guess)
- return GIT_ENOTFOUND;
+ if (!guess) {
+ error = GIT_ENOTFOUND;
+ goto done;
+ }
- return git_buf_puts(out, guess->name);
+ error = git_buf_puts(out, guess->name);
+
+done:
+ git_buf_dispose(&local_default);
+ return error;
}
int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
git_transport *transport;
git_repository *repo;
git_push *push;
- git_transfer_progress stats;
+ git_indexer_progress stats;
unsigned int need_pack;
git_remote_autotag_option_t download_tags;
int prune_refs;
int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn);
-const char* git_remote__urlfordirection(struct git_remote *remote, int direction);
+int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks);
int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url);
git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname);
#include "commit.h"
#include "tag.h"
#include "blob.h"
-#include "fileops.h"
+#include "futils.h"
#include "sysdir.h"
#include "filebuf.h"
#include "index.h"
static const struct {
git_repository_item_t parent;
+ git_repository_item_t fallback;
const char *name;
bool directory;
} items[] = {
- { GIT_REPOSITORY_ITEM_GITDIR, NULL, true },
- { GIT_REPOSITORY_ITEM_WORKDIR, NULL, true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, NULL, true },
- { GIT_REPOSITORY_ITEM_GITDIR, "index", false },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "objects", true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "refs", true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "packed-refs", false },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "remotes", true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "config", false },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "info", true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "hooks", true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "logs", true },
- { GIT_REPOSITORY_ITEM_GITDIR, "modules", true },
- { GIT_REPOSITORY_ITEM_COMMONDIR, "worktrees", true }
+ { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true },
+ { GIT_REPOSITORY_ITEM_WORKDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM__LAST, NULL, true },
+ { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "index", false },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "objects", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "refs", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "packed-refs", false },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "remotes", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "config", false },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "info", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "hooks", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "logs", true },
+ { GIT_REPOSITORY_ITEM_GITDIR, GIT_REPOSITORY_ITEM__LAST, "modules", true },
+ { GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true }
};
-static int check_repositoryformatversion(git_config *config);
+static int check_repositoryformatversion(int *version, git_config *config);
+static int check_extensions(git_config *config, int version);
#define GIT_COMMONDIR_FILE "commondir"
#define GIT_GITDIR_FILE "gitdir"
#define GIT_FILE_CONTENT_PREFIX "gitdir:"
-#define GIT_BRANCH_MASTER "master"
+#define GIT_BRANCH_DEFAULT "master"
#define GIT_REPO_VERSION 0
+#define GIT_REPO_MAX_VERSION 1
git_buf git_repository__reserved_names_win32[] = {
{ DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
git_config_free(config);
}
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
}
static void set_index(git_repository *repo, git_index *index)
}
}
-void git_repository__cleanup(git_repository *repo)
+int git_repository__cleanup(git_repository *repo)
{
assert(repo);
set_index(repo, NULL);
set_odb(repo, NULL);
set_refdb(repo, NULL);
+
+ return 0;
}
void git_repository_free(git_repository *repo)
git_repository__cleanup(repo);
- git_cache_free(&repo->objects);
+ git_cache_dispose(&repo->objects);
git_diff_driver_registry_free(repo->diff_drivers);
repo->diff_drivers = NULL;
*
* Open a repository object from its path
*/
-static bool valid_repository_path(git_buf *repository_path, git_buf *common_path)
+static int is_valid_repository_path(bool *out, git_buf *repository_path, git_buf *common_path)
{
+ int error;
+
+ *out = false;
+
/* Check if we have a separate commondir (e.g. we have a
* worktree) */
if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
git_buf common_link = GIT_BUF_INIT;
- git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE);
- git_futils_readbuffer(&common_link, common_link.ptr);
- git_buf_rtrim(&common_link);
+ if ((error = git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE)) < 0 ||
+ (error = git_futils_readbuffer(&common_link, common_link.ptr)) < 0)
+ return error;
+ git_buf_rtrim(&common_link);
if (git_path_is_relative(common_link.ptr)) {
- git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr);
+ if ((error = git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr)) < 0)
+ return error;
} else {
git_buf_swap(common_path, &common_link);
}
git_buf_dispose(&common_link);
}
else {
- git_buf_set(common_path, repository_path->ptr, repository_path->size);
+ if ((error = git_buf_set(common_path, repository_path->ptr, repository_path->size)) < 0)
+ return error;
}
/* Make sure the commondir path always has a trailing * slash */
if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
- git_buf_putc(common_path, '/');
+ if ((error = git_buf_putc(common_path, '/')) < 0)
+ return error;
/* Ensure HEAD file exists */
if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
- return false;
-
+ return 0;
/* Check files in common dir */
if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
- return false;
+ return 0;
if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
- return false;
+ return 0;
- return true;
+ *out = true;
+ return 0;
}
static git_repository *repository_alloc(void)
if (!repo->reserved_names.ptr)
goto on_error;
- /* set all the entries in the cvar cache to `unset` */
- git_repository__cvar_cache_clear(repo);
+ /* set all the entries in the configmap cache to `unset` */
+ git_repository__configmap_lookup_cache_clear(repo);
return repo;
on_error:
if (repo)
- git_cache_free(&repo->objects);
+ git_cache_dispose(&repo->objects);
git__free(repo);
return NULL;
uint32_t flags,
const char *ceiling_dirs)
{
- int error;
git_buf path = GIT_BUF_INIT;
git_buf repo_link = GIT_BUF_INIT;
git_buf common_link = GIT_BUF_INIT;
struct stat st;
dev_t initial_device = 0;
int min_iterations;
- bool in_dot_git;
+ bool in_dot_git, is_valid;
size_t ceiling_offset = 0;
+ int error;
git_buf_clear(gitdir_path);
for (;;) {
if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
if (!in_dot_git) {
- error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
- if (error < 0)
- break;
+ if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
+ goto out;
}
in_dot_git = !in_dot_git;
}
break;
if (S_ISDIR(st.st_mode)) {
- if (valid_repository_path(&path, &common_link)) {
- git_path_to_dir(&path);
- git_buf_set(gitdir_path, path.ptr, path.size);
+ if ((error = is_valid_repository_path(&is_valid, &path, &common_link)) < 0)
+ goto out;
+
+ if (is_valid) {
+ if ((error = git_path_to_dir(&path)) < 0 ||
+ (error = git_buf_set(gitdir_path, path.ptr, path.size)) < 0)
+ goto out;
if (gitlink_path)
- git_buf_attach(gitlink_path,
- git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
+ if ((error = git_buf_attach(gitlink_path, git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0)) < 0)
+ goto out;
if (commondir_path)
git_buf_swap(&common_link, commondir_path);
break;
}
- }
- else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
- error = read_gitfile(&repo_link, path.ptr);
- if (error < 0)
- break;
- if (valid_repository_path(&repo_link, &common_link)) {
+ } else if (S_ISREG(st.st_mode) && git__suffixcmp(path.ptr, "/" DOT_GIT) == 0) {
+ if ((error = read_gitfile(&repo_link, path.ptr)) < 0 ||
+ (error = is_valid_repository_path(&is_valid, &repo_link, &common_link)) < 0)
+ goto out;
+
+ if (is_valid) {
git_buf_swap(gitdir_path, &repo_link);
if (gitlink_path)
- error = git_buf_put(gitlink_path, path.ptr, path.size);
+ if ((error = git_buf_put(gitlink_path, path.ptr, path.size)) < 0)
+ goto out;
if (commondir_path)
git_buf_swap(&common_link, commondir_path);
}
/* Move up one directory. If we're in_dot_git, we'll search the
* parent itself next. If we're !in_dot_git, we'll search .git
* in the parent directory next (added at the top of the loop). */
- if (git_path_dirname_r(&path, path.ptr) < 0) {
- error = -1;
- break;
- }
+ if ((error = git_path_dirname_r(&path, path.ptr)) < 0)
+ goto out;
/* Once we've checked the directory (and .git if applicable),
* find the ceiling for a search. */
ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
/* Check if we should stop searching here. */
- if (min_iterations == 0
- && (path.ptr[ceiling_offset] == 0
- || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
+ if (min_iterations == 0 &&
+ (path.ptr[ceiling_offset] == 0 || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))
break;
}
- if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
+ if (workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
if (!git_buf_len(gitdir_path))
git_buf_clear(workdir_path);
- else {
- git_path_dirname_r(workdir_path, path.ptr);
- git_path_to_dir(workdir_path);
- }
- if (git_buf_oom(workdir_path))
- return -1;
+ else if ((error = git_path_dirname_r(workdir_path, path.ptr)) < 0 ||
+ (error = git_path_to_dir(workdir_path)) < 0)
+ goto out;
}
/* If we didn't find the repository, and we don't have any other error
* to report, report that. */
- if (!git_buf_len(gitdir_path) && !error) {
- git_error_set(GIT_ERROR_REPOSITORY,
- "could not find repository from '%s'", start_path);
+ if (!git_buf_len(gitdir_path)) {
+ git_error_set(GIT_ERROR_REPOSITORY, "could not find repository from '%s'", start_path);
error = GIT_ENOTFOUND;
+ goto out;
}
+out:
git_buf_dispose(&path);
git_buf_dispose(&repo_link);
git_buf_dispose(&common_link);
git_repository **repo_ptr,
const char *bare_path)
{
- int error;
git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
git_repository *repo = NULL;
+ bool is_valid;
+ int error;
- if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
+ if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0 ||
+ (error = is_valid_repository_path(&is_valid, &path, &common_path)) < 0)
return error;
- if (!valid_repository_path(&path, &common_path)) {
+ if (!is_valid) {
git_buf_dispose(&path);
git_buf_dispose(&common_path);
git_error_set(GIT_ERROR_REPOSITORY, "path is not a repository: %s", bare_path);
unsigned is_worktree;
git_buf gitdir = GIT_BUF_INIT, workdir = GIT_BUF_INIT,
gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
- git_repository *repo;
+ git_repository *repo = NULL;
git_config *config = NULL;
+ int version = 0;
if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
return _git_repository_open_ext_from_env(repo_ptr, start_path);
&gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs);
if (error < 0 || !repo_ptr)
- return error;
+ goto cleanup;
repo = repository_alloc();
GIT_ERROR_CHECK_ALLOC(repo);
if (error < 0 && error != GIT_ENOTFOUND)
goto cleanup;
- if (config && (error = check_repositoryformatversion(config)) < 0)
+ if (config && (error = check_repositoryformatversion(&version, config)) < 0)
+ goto cleanup;
+
+ if ((error = check_extensions(config, version)) < 0)
goto cleanup;
if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0)
cleanup:
git_buf_dispose(&gitdir);
git_buf_dispose(&workdir);
+ git_buf_dispose(&gitlink);
+ git_buf_dispose(&commondir);
git_config_free(config);
if (error < 0)
git_repository_free(repo);
- else
+ else if (repo_ptr)
*repo_ptr = repo;
return error;
{
git_buf path = GIT_BUF_INIT;
git_repository *repo = NULL;
- int len, err;
+ size_t len;
+ int err;
assert(repo_out && wt);
return git_config_snapshot(out, weak);
}
-void git_repository_set_config(git_repository *repo, git_config *config)
+int git_repository_set_config(git_repository *repo, git_config *config)
{
assert(repo && config);
set_config(repo, config);
+ return 0;
}
int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
return 0;
}
-void git_repository_set_odb(git_repository *repo, git_odb *odb)
+int git_repository_set_odb(git_repository *repo, git_odb *odb)
{
assert(repo && odb);
set_odb(repo, odb);
+ return 0;
}
int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
return 0;
}
-void git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
+int git_repository_set_refdb(git_repository *repo, git_refdb *refdb)
{
assert(repo && refdb);
set_refdb(repo, refdb);
+ return 0;
}
int git_repository_index__weakptr(git_index **out, git_repository *repo)
return 0;
}
-void git_repository_set_index(git_repository *repo, git_index *index)
+int git_repository_set_index(git_repository *repo, git_index *index)
{
assert(repo);
set_index(repo, index);
+ return 0;
}
int git_repository_set_namespace(git_repository *repo, const char *namespace)
int (*prefixcmp)(const char *, const char *);
int error, ignorecase;
- error = git_repository__cvar(
- &ignorecase, repo, GIT_CVAR_IGNORECASE);
+ error = git_repository__configmap_lookup(
+ &ignorecase, repo, GIT_CONFIGMAP_IGNORECASE);
prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
git__prefixcmp;
}
#endif
-static int check_repositoryformatversion(git_config *config)
+static int check_repositoryformatversion(int *version, git_config *config)
{
- int version, error;
+ int error;
- error = git_config_get_int32(&version, config, "core.repositoryformatversion");
+ error = git_config_get_int32(version, config, "core.repositoryformatversion");
/* git ignores this if the config variable isn't there */
if (error == GIT_ENOTFOUND)
return 0;
if (error < 0)
return -1;
- if (GIT_REPO_VERSION < version) {
+ if (GIT_REPO_MAX_VERSION < *version) {
git_error_set(GIT_ERROR_REPOSITORY,
- "unsupported repository version %d. Only versions up to %d are supported.",
- version, GIT_REPO_VERSION);
+ "unsupported repository version %d; only versions up to %d are supported",
+ *version, GIT_REPO_MAX_VERSION);
return -1;
}
return 0;
}
+static int check_valid_extension(const git_config_entry *entry, void *payload)
+{
+ GIT_UNUSED(payload);
+
+ if (!strcmp(entry->name, "extensions.noop"))
+ return 0;
+
+ git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name);
+ return -1;
+}
+
+static int check_extensions(git_config *config, int version)
+{
+ if (version < 1)
+ return 0;
+
+ return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL);
+}
+
int git_repository_create_head(const char *git_dir, const char *ref_name)
{
git_buf ref_path = GIT_BUF_INIT;
git_filebuf ref = GIT_FILEBUF_INIT;
const char *fmt;
+ int error;
- if (git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE) < 0 ||
- git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE) < 0)
- goto fail;
-
- if (!ref_name)
- ref_name = GIT_BRANCH_MASTER;
+ if ((error = git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) < 0 ||
+ (error = git_filebuf_open(&ref, ref_path.ptr, 0, GIT_REFS_FILE_MODE)) < 0)
+ goto out;
if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0)
fmt = "ref: %s\n";
else
fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n";
- if (git_filebuf_printf(&ref, fmt, ref_name) < 0 ||
- git_filebuf_commit(&ref) < 0)
- goto fail;
-
- git_buf_dispose(&ref_path);
- return 0;
+ if ((error = git_filebuf_printf(&ref, fmt, ref_name)) < 0 ||
+ (error = git_filebuf_commit(&ref)) < 0)
+ goto out;
-fail:
+out:
git_buf_dispose(&ref_path);
git_filebuf_cleanup(&ref);
- return -1;
+ return error;
}
static bool is_chmod_supported(const char *file_path)
git_buf xdg_buf = GIT_BUF_INIT;
git_buf system_buf = GIT_BUF_INIT;
git_buf programdata_buf = GIT_BUF_INIT;
- git_buf path = GIT_BUF_INIT;
- int fd;
- struct stat st;
int symlinks = 0;
/*
goto done;
#endif
- if ((fd = git_futils_mktmp(&path, wd_path, 0666)) < 0 ||
- p_close(fd) < 0 ||
- p_unlink(path.ptr) < 0 ||
- p_symlink("testing", path.ptr) < 0 ||
- p_lstat(path.ptr, &st) < 0)
+ if (!(symlinks = git_path_supports_symlinks(wd_path)))
goto done;
- symlinks = (S_ISLNK(st.st_mode) != 0);
-
- (void)p_unlink(path.ptr);
-
done:
git_buf_dispose(&global_buf);
git_buf_dispose(&xdg_buf);
git_buf_dispose(&system_buf);
git_buf_dispose(&programdata_buf);
- git_buf_dispose(&path);
git_config_free(config);
return symlinks != 0;
}
git_config *config = NULL;
bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
+ int version = 0;
if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
goto cleanup;
- if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
+ if (is_reinit && (error = check_repositoryformatversion(&version, config)) < 0)
+ goto cleanup;
+
+ if ((error = check_extensions(config, version)) < 0)
goto cleanup;
#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
git_config_free(config);
git_buf_dispose(&path);
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
if (!repo->is_bare && recurse)
(void)git_submodule_foreach(repo, repo_reinit_submodule_fs, NULL);
return error;
}
+static int repo_init_head(const char *repo_dir, const char *given)
+{
+ git_config *cfg = NULL;
+ git_buf head_path = GIT_BUF_INIT, cfg_branch = GIT_BUF_INIT;
+ const char *initial_head = NULL;
+ int error;
+
+ if ((error = git_buf_joinpath(&head_path, repo_dir, GIT_HEAD_FILE)) < 0)
+ goto out;
+
+ /*
+ * A template may have set a HEAD; use that unless it's been
+ * overridden by the caller's given initial head setting.
+ */
+ if (git_path_exists(head_path.ptr) && !given)
+ goto out;
+
+ if (given) {
+ initial_head = given;
+ } else if ((error = git_config_open_default(&cfg)) >= 0 &&
+ (error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0) {
+ initial_head = cfg_branch.ptr;
+ }
+
+ if (!initial_head)
+ initial_head = GIT_BRANCH_DEFAULT;
+
+ error = git_repository_create_head(repo_dir, initial_head);
+
+out:
+ git_config_free(cfg);
+ git_buf_dispose(&head_path);
+ git_buf_dispose(&cfg_branch);
+
+ return error;
+}
+
static int repo_init_create_origin(git_repository *repo, const char *url)
{
int error;
const char *given_repo,
git_repository_init_options *opts)
{
- int error;
git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT,
common_path = GIT_BUF_INIT;
const char *wd;
+ bool is_valid;
+ int error;
assert(out && given_repo && opts);
GIT_ERROR_CHECK_VERSION(opts, GIT_REPOSITORY_INIT_OPTIONS_VERSION, "git_repository_init_options");
- error = repo_init_directories(&repo_path, &wd_path, given_repo, opts);
- if (error < 0)
- goto cleanup;
+ if ((error = repo_init_directories(&repo_path, &wd_path, given_repo, opts)) < 0)
+ goto out;
wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
- if (valid_repository_path(&repo_path, &common_path)) {
+ if ((error = is_valid_repository_path(&is_valid, &repo_path, &common_path)) < 0)
+ goto out;
+
+ if (is_valid) {
if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
git_error_set(GIT_ERROR_REPOSITORY,
"attempt to reinitialize '%s'", given_repo);
error = GIT_EEXISTS;
- goto cleanup;
+ goto out;
}
opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT;
- error = repo_init_config(
- repo_path.ptr, wd, opts->flags, opts->mode);
+ if ((error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0)
+ goto out;
/* TODO: reinitialize the templates */
+ } else {
+ if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 ||
+ (error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0 ||
+ (error = repo_init_head(repo_path.ptr, opts->initial_head)) < 0)
+ goto out;
}
- else {
- if (!(error = repo_init_structure(
- repo_path.ptr, wd, opts)) &&
- !(error = repo_init_config(
- repo_path.ptr, wd, opts->flags, opts->mode)))
- error = git_repository_create_head(
- repo_path.ptr, opts->initial_head);
- }
- if (error < 0)
- goto cleanup;
- error = git_repository_open(out, repo_path.ptr);
+ if ((error = git_repository_open(out, repo_path.ptr)) < 0)
+ goto out;
- if (!error && opts->origin_url)
- error = repo_init_create_origin(*out, opts->origin_url);
+ if (opts->origin_url &&
+ (error = repo_init_create_origin(*out, opts->origin_url)) < 0)
+ goto out;
-cleanup:
+out:
git_buf_dispose(&common_path);
git_buf_dispose(&repo_path);
git_buf_dispose(&wd_path);
return exists;
}
-static int get_worktree_file_path(git_buf *out, git_repository *repo, const char *worktree, const char *file)
-{
- git_buf_clear(out);
- return git_buf_printf(out, "%s/worktrees/%s/%s", repo->commondir, worktree, file);
-}
-
int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
{
git_reference *ref = NULL;
int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
{
- git_buf path = GIT_BUF_INIT;
+ git_repository *worktree_repo = NULL;
+ git_worktree *worktree = NULL;
git_reference *head = NULL;
int error;
*out = NULL;
- if ((error = get_worktree_file_path(&path, repo, name, GIT_HEAD_FILE)) < 0 ||
- (error = git_reference__read_head(&head, repo, path.ptr)) < 0)
+ if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 ||
+ (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 ||
+ (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0)
goto out;
if (git_reference_type(head) != GIT_REFERENCE_DIRECT) {
- git_reference *resolved;
-
- error = git_reference_lookup_resolved(&resolved, repo, git_reference_symbolic_target(head), -1);
- git_reference_free(head);
- head = resolved;
+ if ((error = git_reference_lookup_resolved(out, worktree_repo, git_reference_symbolic_target(head), -1)) < 0)
+ goto out;
+ } else {
+ *out = head;
+ head = NULL;
}
- *out = head;
-
out:
- if (error)
- git_reference_free(head);
-
- git_buf_dispose(&path);
-
+ git_reference_free(head);
+ git_worktree_free(worktree);
+ git_repository_free(worktree_repo);
return error;
}
-int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload)
+int git_repository_foreach_worktree(git_repository *repo,
+ git_repository_foreach_worktree_cb cb,
+ void *payload)
{
- git_strarray worktrees = GIT_VECTOR_INIT;
- git_buf path = GIT_BUF_INIT;
+ git_strarray worktrees = {0};
+ git_repository *worktree_repo = NULL;
+ git_worktree *worktree = NULL;
int error;
size_t i;
- /* Execute callback for HEAD of commondir */
- if ((error = git_buf_joinpath(&path, repo->commondir, GIT_HEAD_FILE)) < 0 ||
- (error = cb(repo, path.ptr, payload) != 0))
+ if ((error = git_repository_open(&worktree_repo, repo->commondir)) < 0 ||
+ (error = cb(worktree_repo, payload) != 0))
goto out;
- if ((error = git_worktree_list(&worktrees, repo)) < 0) {
- error = 0;
+ git_repository_free(worktree_repo);
+ worktree_repo = NULL;
+
+ if ((error = git_worktree_list(&worktrees, repo)) < 0)
goto out;
- }
- /* Execute callback for all worktree HEADs */
for (i = 0; i < worktrees.count; i++) {
- if (get_worktree_file_path(&path, repo, worktrees.strings[i], GIT_HEAD_FILE) < 0)
+ git_repository_free(worktree_repo);
+ worktree_repo = NULL;
+ git_worktree_free(worktree);
+ worktree = NULL;
+
+ if ((error = git_worktree_lookup(&worktree, repo, worktrees.strings[i]) < 0) ||
+ (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto out;
+ error = 0;
continue;
+ }
- if ((error = cb(repo, path.ptr, payload)) != 0)
+ if ((error = cb(worktree_repo, payload)) != 0)
goto out;
}
out:
- git_buf_dispose(&path);
- git_strarray_free(&worktrees);
+ git_strarray_dispose(&worktrees);
+ git_repository_free(worktree_repo);
+ git_worktree_free(worktree);
return error;
}
return error;
}
+int git_repository_initialbranch(git_buf *out, git_repository *repo)
+{
+ git_config *config;
+ git_config_entry *entry = NULL;
+ const char *branch;
+ int error;
+
+ if ((error = git_repository_config__weakptr(&config, repo)) < 0)
+ return error;
+
+ if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0) {
+ branch = entry->value;
+ }
+ else if (error == GIT_ENOTFOUND) {
+ branch = GIT_BRANCH_DEFAULT;
+ }
+ else {
+ goto done;
+ }
+
+ if ((error = git_buf_puts(out, GIT_REFS_HEADS_DIR)) < 0 ||
+ (error = git_buf_puts(out, branch)) < 0)
+ goto done;
+
+ if (!git_reference_is_valid_name(out->ptr)) {
+ git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid reference name");
+ error = -1;
+ }
+
+done:
+ git_config_entry_free(entry);
+ return error;
+}
+
int git_repository_is_empty(git_repository *repo)
{
git_reference *head = NULL;
- int is_empty = 0;
+ git_buf initialbranch = GIT_BUF_INIT;
+ int result = 0;
- if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0)
- return -1;
+ if ((result = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0 ||
+ (result = git_repository_initialbranch(&initialbranch, repo)) < 0)
+ goto done;
- if (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC)
- is_empty =
- (strcmp(git_reference_symbolic_target(head),
- GIT_REFS_HEADS_DIR "master") == 0) &&
- repo_contains_no_reference(repo);
+ result = (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC &&
+ strcmp(git_reference_symbolic_target(head), initialbranch.ptr) == 0 &&
+ repo_contains_no_reference(repo));
+done:
git_reference_free(head);
+ git_buf_dispose(&initialbranch);
- return is_empty;
+ return result;
}
-int git_repository_item_path(git_buf *out, const git_repository *repo, git_repository_item_t item)
+static const char *resolved_parent_path(const git_repository *repo, git_repository_item_t item, git_repository_item_t fallback)
{
const char *parent;
- switch (items[item].parent) {
+ switch (item) {
case GIT_REPOSITORY_ITEM_GITDIR:
parent = git_repository_path(repo);
break;
break;
default:
git_error_set(GIT_ERROR_INVALID, "invalid item directory");
- return -1;
+ return NULL;
}
+ if (!parent && fallback != GIT_REPOSITORY_ITEM__LAST)
+ return resolved_parent_path(repo, fallback, GIT_REPOSITORY_ITEM__LAST);
+
+ return parent;
+}
+int git_repository_item_path(git_buf *out, const git_repository *repo, git_repository_item_t item)
+{
+ const char *parent = resolved_parent_path(repo, items[item].parent, items[item].fallback);
if (parent == NULL) {
git_error_set(GIT_ERROR_INVALID, "path cannot exist in repository");
return GIT_ENOTFOUND;
git_oid_fmt(orig_head_str, orig_head);
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 &&
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 &&
(error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
error = git_filebuf_commit(&file);
int error;
git_filter_list *fl = NULL;
git_file fd = -1;
- git_off_t len;
+ uint64_t len;
git_buf full_path = GIT_BUF_INIT;
assert(out && path && repo); /* as_path can be NULL */
goto cleanup;
}
- len = git_futils_filesize(fd);
- if (len < 0) {
- error = (int)len;
+ if ((error = git_futils_filesize(&len, fd)) < 0)
goto cleanup;
- }
if (!git__is_sizet(len)) {
git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
return st.st_size == 0 ? 0 : 1;
}
-int git_repository_init_init_options(
+int git_repository_init_options_init(
git_repository_init_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_repository_init_init_options(
+ git_repository_init_options *opts, unsigned int version)
+{
+ return git_repository_init_options_init(opts, version);
+}
+#endif
+
int git_repository_ident(const char **name, const char **email, const git_repository *repo)
{
*name = repo->ident_name;
assert(repo);
- if ((error = git_strmap_alloc(&repo->submodule_cache)))
+ if ((error = git_strmap_new(&repo->submodule_cache)))
return error;
error = git_submodule__map(repo, repo->submodule_cache);
/** Cvar cache identifiers */
typedef enum {
- GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */
- GIT_CVAR_EOL, /* core.eol */
- GIT_CVAR_SYMLINKS, /* core.symlinks */
- GIT_CVAR_IGNORECASE, /* core.ignorecase */
- GIT_CVAR_FILEMODE, /* core.filemode */
- GIT_CVAR_IGNORESTAT, /* core.ignorestat */
- GIT_CVAR_TRUSTCTIME, /* core.trustctime */
- GIT_CVAR_ABBREV, /* core.abbrev */
- GIT_CVAR_PRECOMPOSE, /* core.precomposeunicode */
- GIT_CVAR_SAFE_CRLF, /* core.safecrlf */
- GIT_CVAR_LOGALLREFUPDATES, /* core.logallrefupdates */
- GIT_CVAR_PROTECTHFS, /* core.protectHFS */
- GIT_CVAR_PROTECTNTFS, /* core.protectNTFS */
- GIT_CVAR_FSYNCOBJECTFILES, /* core.fsyncObjectFiles */
- GIT_CVAR_CACHE_MAX
-} git_cvar_cached;
+ GIT_CONFIGMAP_AUTO_CRLF = 0, /* core.autocrlf */
+ GIT_CONFIGMAP_EOL, /* core.eol */
+ GIT_CONFIGMAP_SYMLINKS, /* core.symlinks */
+ GIT_CONFIGMAP_IGNORECASE, /* core.ignorecase */
+ GIT_CONFIGMAP_FILEMODE, /* core.filemode */
+ GIT_CONFIGMAP_IGNORESTAT, /* core.ignorestat */
+ GIT_CONFIGMAP_TRUSTCTIME, /* core.trustctime */
+ GIT_CONFIGMAP_ABBREV, /* core.abbrev */
+ GIT_CONFIGMAP_PRECOMPOSE, /* core.precomposeunicode */
+ GIT_CONFIGMAP_SAFE_CRLF, /* core.safecrlf */
+ GIT_CONFIGMAP_LOGALLREFUPDATES, /* core.logallrefupdates */
+ GIT_CONFIGMAP_PROTECTHFS, /* core.protectHFS */
+ GIT_CONFIGMAP_PROTECTNTFS, /* core.protectNTFS */
+ GIT_CONFIGMAP_FSYNCOBJECTFILES, /* core.fsyncObjectFiles */
+ GIT_CONFIGMAP_CACHE_MAX
+} git_configmap_item;
/**
- * CVAR value enumerations
+ * Configuration map value enumerations
*
- * These are the values that are actually stored in the cvar cache, instead
- * of their string equivalents. These values are internal and symbolic;
- * make sure that none of them is set to `-1`, since that is the unique
- * identifier for "not cached"
+ * These are the values that are actually stored in the configmap cache,
+ * instead of their string equivalents. These values are internal and
+ * symbolic; make sure that none of them is set to `-1`, since that is
+ * the unique identifier for "not cached"
*/
typedef enum {
/* The value hasn't been loaded from the cache yet */
- GIT_CVAR_NOT_CACHED = -1,
+ GIT_CONFIGMAP_NOT_CACHED = -1,
/* core.safecrlf: false, 'fail', 'warn' */
GIT_SAFE_CRLF_FALSE = 0,
GIT_EOL_DEFAULT = GIT_EOL_NATIVE,
/* core.symlinks: bool */
- GIT_SYMLINKS_DEFAULT = GIT_CVAR_TRUE,
+ GIT_SYMLINKS_DEFAULT = GIT_CONFIGMAP_TRUE,
/* core.ignorecase */
- GIT_IGNORECASE_DEFAULT = GIT_CVAR_FALSE,
+ GIT_IGNORECASE_DEFAULT = GIT_CONFIGMAP_FALSE,
/* core.filemode */
- GIT_FILEMODE_DEFAULT = GIT_CVAR_TRUE,
+ GIT_FILEMODE_DEFAULT = GIT_CONFIGMAP_TRUE,
/* core.ignorestat */
- GIT_IGNORESTAT_DEFAULT = GIT_CVAR_FALSE,
+ GIT_IGNORESTAT_DEFAULT = GIT_CONFIGMAP_FALSE,
/* core.trustctime */
- GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE,
+ GIT_TRUSTCTIME_DEFAULT = GIT_CONFIGMAP_TRUE,
/* core.abbrev */
GIT_ABBREV_DEFAULT = 7,
/* core.precomposeunicode */
- GIT_PRECOMPOSE_DEFAULT = GIT_CVAR_FALSE,
+ GIT_PRECOMPOSE_DEFAULT = GIT_CONFIGMAP_FALSE,
/* core.safecrlf */
- GIT_SAFE_CRLF_DEFAULT = GIT_CVAR_FALSE,
+ GIT_SAFE_CRLF_DEFAULT = GIT_CONFIGMAP_FALSE,
/* core.logallrefupdates */
- GIT_LOGALLREFUPDATES_FALSE = GIT_CVAR_FALSE,
- GIT_LOGALLREFUPDATES_TRUE = GIT_CVAR_TRUE,
+ GIT_LOGALLREFUPDATES_FALSE = GIT_CONFIGMAP_FALSE,
+ GIT_LOGALLREFUPDATES_TRUE = GIT_CONFIGMAP_TRUE,
GIT_LOGALLREFUPDATES_UNSET = 2,
GIT_LOGALLREFUPDATES_ALWAYS = 3,
GIT_LOGALLREFUPDATES_DEFAULT = GIT_LOGALLREFUPDATES_UNSET,
/* core.protectHFS */
- GIT_PROTECTHFS_DEFAULT = GIT_CVAR_FALSE,
+ GIT_PROTECTHFS_DEFAULT = GIT_CONFIGMAP_FALSE,
/* core.protectNTFS */
- GIT_PROTECTNTFS_DEFAULT = GIT_CVAR_TRUE,
+ GIT_PROTECTNTFS_DEFAULT = GIT_CONFIGMAP_TRUE,
/* core.fsyncObjectFiles */
- GIT_FSYNCOBJECTFILES_DEFAULT = GIT_CVAR_FALSE,
-} git_cvar_value;
+ GIT_FSYNCOBJECTFILES_DEFAULT = GIT_CONFIGMAP_FALSE,
+} git_configmap_value;
/* internal repository init flags */
enum {
git_atomic attr_session_key;
- git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX];
+ git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
git_strmap *submodule_cache;
};
int git_repository_head_tree(git_tree **tree, git_repository *repo);
int git_repository_create_head(const char *git_dir, const char *ref_name);
-/*
- * Called for each HEAD.
- *
- * Can return either 0, causing the iteration over HEADs to
- * continue, or a non-0 value causing the iteration to abort. The
- * return value is passed back to the caller of
- * `git_repository_foreach_head`
- */
-typedef int (*git_repository_foreach_head_cb)(git_repository *repo, const char *path, void *payload);
+typedef int (*git_repository_foreach_worktree_cb)(git_repository *, void *);
-/*
- * Iterate over repository and all worktree HEADs.
- *
- * This function will be called for the repository HEAD and for
- * all HEADS of linked worktrees. For each HEAD, the callback is
- * executed with the given payload. The return value equals the
- * return value of the last executed callback function.
- */
-int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload);
+int git_repository_foreach_worktree(git_repository *repo,
+ git_repository_foreach_worktree_cb cb,
+ void *payload);
/*
* Weak pointers to repository internals.
int git_repository_index__weakptr(git_index **out, git_repository *repo);
/*
- * CVAR cache
+ * Configuration map cache
*
* Efficient access to the most used config variables of a repository.
* The cache is cleared every time the config backend is replaced.
*/
-int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar);
-void git_repository__cvar_cache_clear(git_repository *repo);
+int git_repository__configmap_lookup(int *out, git_repository *repo, git_configmap_item item);
+void git_repository__configmap_lookup_cache_clear(git_repository *repo);
GIT_INLINE(int) git_repository__ensure_not_bare(
git_repository *repo,
bool git_repository__reserved_names(
git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs);
+/*
+ * The default branch for the repository; the `init.defaultBranch`
+ * configuration option, if set, or `master` if it is not.
+ */
+int git_repository_initialbranch(git_buf *out, git_repository *repo);
+
#endif
int error = 0;
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_REVERT_HEAD_FILE)) >= 0 &&
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_REVERT_FILE_MODE)) >= 0 &&
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_REVERT_FILE_MODE)) >= 0 &&
(error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0)
error = git_filebuf_commit(&file);
int error = 0;
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_REVERT_FILE_MODE)) < 0 ||
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_REVERT_FILE_MODE)) < 0 ||
(error = git_filebuf_printf(&file, "Revert \"%s\"\n\nThis reverts commit %s.\n",
commit_msgline, commit_oidstr)) < 0)
goto cleanup;
return error;
}
-int git_revert_init_options(git_revert_options *opts, unsigned int version)
+int git_revert_options_init(git_revert_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_revert_options, GIT_REVERT_OPTIONS_INIT);
return 0;
}
+
+#ifndef GIT_DEPRECATE_HARD
+int git_revert_init_options(git_revert_options *opts, unsigned int version)
+{
+ return git_revert_options_init(opts, version);
+}
+#endif
#include "common.h"
-#include <assert.h>
-
#include "buffer.h"
#include "tree.h"
#include "refdb.h"
+#include "regexp.h"
#include "git2.h"
return maybe_sha_or_abbrev(out, repo, spec, speclen);
}
-static int build_regex(regex_t *regex, const char *pattern)
+static int build_regex(git_regexp *regex, const char *pattern)
{
int error;
return GIT_EINVALIDSPEC;
}
- error = p_regcomp(regex, pattern, REG_EXTENDED);
+ error = git_regexp_compile(regex, pattern, 0);
if (!error)
return 0;
- error = git_error_set_regex(regex, error);
-
- regfree(regex);
+ git_regexp_dispose(regex);
return error;
}
{
const char *substr;
int error;
- regex_t regex;
+ git_regexp regex;
substr = strstr(spec, "-g");
if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0)
return -1;
- error = regexec(®ex, spec, 0, NULL, 0);
- regfree(®ex);
+ error = git_regexp_match(®ex, spec);
+ git_regexp_dispose(®ex);
if (error)
return GIT_ENOTFOUND;
{
git_reference *ref = NULL;
git_reflog *reflog = NULL;
- regex_t preg;
+ git_regexp preg;
int error = -1;
size_t i, numentries, cur;
const git_reflog_entry *entry;
const char *msg;
- regmatch_t regexmatches[2];
git_buf buf = GIT_BUF_INIT;
cur = position;
numentries = git_reflog_entrycount(reflog);
for (i = 0; i < numentries; i++) {
+ git_regmatch regexmatches[2];
+
entry = git_reflog_entry_byindex(reflog, i);
msg = git_reflog_entry_message(entry);
if (!msg)
continue;
- if (regexec(&preg, msg, 2, regexmatches, 0))
+ if (git_regexp_search(&preg, msg, 2, regexmatches) < 0)
continue;
cur--;
if (cur > 0)
continue;
- git_buf_put(&buf, msg+regexmatches[1].rm_so, regexmatches[1].rm_eo - regexmatches[1].rm_so);
+ if ((git_buf_put(&buf, msg+regexmatches[1].start, regexmatches[1].end - regexmatches[1].start)) < 0)
+ goto cleanup;
if ((error = git_reference_dwim(base_ref, repo, git_buf_cstr(&buf))) == 0)
goto cleanup;
cleanup:
git_reference_free(ref);
git_buf_dispose(&buf);
- regfree(&preg);
+ git_regexp_dispose(&preg);
git_reflog_free(reflog);
return error;
}
return error;
}
-static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex)
+static int walk_and_search(git_object **out, git_revwalk *walk, git_regexp *regex)
{
int error;
git_oid oid;
if ((error < 0) && (error != GIT_ENOTFOUND))
return -1;
- if (!regexec(regex, git_commit_message((git_commit*)obj), 0, NULL, 0)) {
+ if (!git_regexp_match(regex, git_commit_message((git_commit*)obj))) {
*out = obj;
return 0;
}
static int handle_grep_syntax(git_object **out, git_repository *repo, const git_oid *spec_oid, const char *pattern)
{
- regex_t preg;
+ git_regexp preg;
git_revwalk *walk = NULL;
int error;
error = walk_and_search(out, walk, &preg);
cleanup:
- regfree(&preg);
+ git_regexp_dispose(&preg);
git_revwalk_free(walk);
return error;
if (spec[*pos] == '\0')
return GIT_EINVALIDSPEC;
- git_buf_putc(buf, spec[(*pos)++]);
+ if (git_buf_putc(buf, spec[(*pos)++]) < 0)
+ return -1;
}
(*pos)++;
*pos = end_ptr - spec;
}
- } while (spec[(*pos)] == kind && kind == '~');
+ } while (spec[(*pos)] == kind && kind == '~');
*n = accumulated;
return GIT_EINVALIDSPEC;
}
-int revparse__ext(
+static int revparse(
git_object **object_out,
git_reference **reference_out,
size_t *identifier_len_out,
git_object *obj = NULL;
git_reference *ref = NULL;
- if ((error = revparse__ext(&obj, &ref, &identifier_len, repo, spec)) < 0)
+ if ((error = revparse(&obj, &ref, &identifier_len, repo, spec)) < 0)
goto cleanup;
*object_out = obj;
git_revwalk *walk, const git_oid *oid)
{
git_commit_list_node *commit;
- size_t pos;
- int ret;
/* lookup and reserve space if not already present */
- pos = git_oidmap_lookup_index(walk->commits, oid);
- if (git_oidmap_valid_index(walk->commits, pos))
- return git_oidmap_value_at(walk->commits, pos);
+ if ((commit = git_oidmap_get(walk->commits, oid)) != NULL)
+ return commit;
commit = git_commit_list_alloc_node(walk);
if (commit == NULL)
git_oid_cpy(&commit->oid, oid);
- pos = git_oidmap_put(walk->commits, &commit->oid, &ret);
- assert(ret != 0);
- git_oidmap_set_value_at(walk->commits, pos, commit);
+ if ((git_oidmap_set(walk->commits, &commit->oid, commit)) < 0)
+ return NULL;
return commit;
}
-static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
+int git_revwalk__push_commit(git_revwalk *walk, const git_oid *oid, const git_revwalk__push_options *opts)
{
git_oid commit_id;
int error;
if (error == GIT_ENOTFOUND || error == GIT_EINVALIDSPEC || error == GIT_EPEEL) {
/* If this comes from e.g. push_glob("tags"), ignore this */
- if (from_glob)
+ if (opts->from_glob)
return 0;
git_error_set(GIT_ERROR_INVALID, "object is not a committish");
- return -1;
+ return error;
}
if (error < 0)
return error;
if (commit->uninteresting)
return 0;
- if (uninteresting) {
+ if (opts->uninteresting) {
walk->limited = 1;
walk->did_hide = 1;
} else {
walk->did_push = 1;
}
- commit->uninteresting = uninteresting;
+ commit->uninteresting = opts->uninteresting;
list = walk->user_input;
- if (git_commit_list_insert(commit, &list) == NULL) {
+ if ((opts->insert_by_date &&
+ git_commit_list_insert_by_date(commit, &list) == NULL) ||
+ git_commit_list_insert(commit, &list) == NULL) {
git_error_set_oom();
return -1;
}
int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
+
assert(walk && oid);
- return push_commit(walk, oid, 0, false);
+
+ return git_revwalk__push_commit(walk, oid, &opts);
}
int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk && oid);
- return push_commit(walk, oid, 1, false);
+
+ opts.uninteresting = 1;
+ return git_revwalk__push_commit(walk, oid, &opts);
}
-static int push_ref(git_revwalk *walk, const char *refname, int hide, int from_glob)
+int git_revwalk__push_ref(git_revwalk *walk, const char *refname, const git_revwalk__push_options *opts)
{
git_oid oid;
if (git_reference_name_to_id(&oid, walk->repo, refname) < 0)
return -1;
- return push_commit(walk, &oid, hide, from_glob);
+ return git_revwalk__push_commit(walk, &oid, opts);
}
-static int push_glob(git_revwalk *walk, const char *glob, int hide)
+int git_revwalk__push_glob(git_revwalk *walk, const char *glob, const git_revwalk__push_options *given_opts)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
int error = 0;
git_buf buf = GIT_BUF_INIT;
git_reference *ref;
assert(walk && glob);
+ if (given_opts)
+ memcpy(&opts, given_opts, sizeof(opts));
+
/* refs/ is implied if not given in the glob */
if (git__prefixcmp(glob, GIT_REFS_DIR) != 0)
git_buf_joinpath(&buf, GIT_REFS_DIR, glob);
if ((error = git_reference_iterator_glob_new(&iter, walk->repo, buf.ptr)) < 0)
goto out;
+ opts.from_glob = true;
while ((error = git_reference_next(&ref, iter)) == 0) {
- error = push_ref(walk, git_reference_name(ref), hide, true);
+ error = git_revwalk__push_ref(walk, git_reference_name(ref), &opts);
git_reference_free(ref);
if (error < 0)
break;
int git_revwalk_push_glob(git_revwalk *walk, const char *glob)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk && glob);
- return push_glob(walk, glob, 0);
+
+ return git_revwalk__push_glob(walk, glob, &opts);
}
int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk && glob);
- return push_glob(walk, glob, 1);
+
+ opts.uninteresting = 1;
+ return git_revwalk__push_glob(walk, glob, &opts);
}
int git_revwalk_push_head(git_revwalk *walk)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk);
- return push_ref(walk, GIT_HEAD_FILE, 0, false);
+
+ return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
}
int git_revwalk_hide_head(git_revwalk *walk)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk);
- return push_ref(walk, GIT_HEAD_FILE, 1, false);
+
+ opts.uninteresting = 1;
+ return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts);
}
int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk && refname);
- return push_ref(walk, refname, 0, false);
+
+ return git_revwalk__push_ref(walk, refname, &opts);
}
int git_revwalk_push_range(git_revwalk *walk, const char *range)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
git_revspec revspec;
int error = 0;
if ((error = git_revparse(&revspec, walk->repo, range)))
return error;
+ if (!revspec.to) {
+ git_error_set(GIT_ERROR_INVALID, "invalid revspec: range not provided");
+ error = GIT_EINVALIDSPEC;
+ goto out;
+ }
+
if (revspec.flags & GIT_REVPARSE_MERGE_BASE) {
/* TODO: support "<commit>...<commit>" */
git_error_set(GIT_ERROR_INVALID, "symmetric differences not implemented in revwalk");
- return GIT_EINVALIDSPEC;
+ error = GIT_EINVALIDSPEC;
+ goto out;
}
- if ((error = push_commit(walk, git_object_id(revspec.from), 1, false)))
+ opts.uninteresting = 1;
+ if ((error = git_revwalk__push_commit(walk, git_object_id(revspec.from), &opts)))
goto out;
- error = push_commit(walk, git_object_id(revspec.to), 0, false);
+ opts.uninteresting = 0;
+ error = git_revwalk__push_commit(walk, git_object_id(revspec.to), &opts);
out:
git_object_free(revspec.from);
int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
{
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
assert(walk && refname);
- return push_ref(walk, refname, 1, false);
+ opts.uninteresting = 1;
+ return git_revwalk__push_ref(walk, refname, &opts);
}
static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit)
git_revwalk *walk = git__calloc(1, sizeof(git_revwalk));
GIT_ERROR_CHECK_ALLOC(walk);
- walk->commits = git_oidmap_alloc();
- GIT_ERROR_CHECK_ALLOC(walk->commits);
-
- if (git_pqueue_init(&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0)
+ if (git_oidmap_new(&walk->commits) < 0 ||
+ git_pqueue_init(&walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 ||
+ git_pool_init(&walk->commit_pool, COMMIT_ALLOC) < 0)
return -1;
- git_pool_init(&walk->commit_pool, COMMIT_ALLOC);
walk->get_next = &revwalk_next_unsorted;
walk->enqueue = &revwalk_enqueue_unsorted;
return walk->repo;
}
-void git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
+int git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
{
assert(walk);
if (walk->sorting != GIT_SORT_NONE)
walk->limited = 1;
+
+ return 0;
}
-void git_revwalk_simplify_first_parent(git_revwalk *walk)
+int git_revwalk_simplify_first_parent(git_revwalk *walk)
{
walk->first_parent = 1;
+ return 0;
}
int git_revwalk_next(git_oid *oid, git_revwalk *walk)
return error;
}
-void git_revwalk_reset(git_revwalk *walk)
+int git_revwalk_reset(git_revwalk *walk)
{
git_commit_list_node *commit;
walk->limited = 0;
walk->did_push = walk->did_hide = 0;
walk->sorting = GIT_SORT_NONE;
+
+ return 0;
}
int git_revwalk_add_hide_cb(
git_commit_list_node *git_revwalk__commit_lookup(git_revwalk *walk, const git_oid *oid);
+typedef struct {
+ int uninteresting;
+ int from_glob;
+ int insert_by_date;
+} git_revwalk__push_options;
+
+#define GIT_REVWALK__PUSH_OPTIONS_INIT { 0 }
+
+int git_revwalk__push_commit(git_revwalk *walk,
+ const git_oid *oid,
+ const git_revwalk__push_options *opts);
+
+int git_revwalk__push_ref(git_revwalk *walk,
+ const char *refname,
+ const git_revwalk__push_options *opts);
+
+int git_revwalk__push_glob(git_revwalk *walk,
+ const char *glob,
+ const git_revwalk__push_options *given_opts);
+
#endif
#include "refs.h"
#include "index.h"
#include "transports/smart.h"
+#include "transports/http.h"
#include "streams/openssl.h"
#include "streams/mbedtls.h"
-void git_libgit2_version(int *major, int *minor, int *rev)
+int git_libgit2_version(int *major, int *minor, int *rev)
{
*major = LIBGIT2_VER_MAJOR;
*minor = LIBGIT2_VER_MINOR;
*rev = LIBGIT2_VER_REVISION;
+
+ return 0;
}
int git_libgit2_features(void)
/* Declarations for tuneable settings */
extern size_t git_mwindow__window_size;
extern size_t git_mwindow__mapped_limit;
+extern size_t git_mwindow__file_limit;
extern size_t git_indexer__max_objects;
+extern bool git_disable_pack_keep_file_checks;
static int config_level_to_sysdir(int config_level)
{
*(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
break;
+ case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
+ git_mwindow__file_limit = va_arg(ap, size_t);
+ break;
+
+ case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
+ *(va_arg(ap, size_t *)) = git_mwindow__file_limit;
+ break;
+
case GIT_OPT_GET_SEARCH_PATH:
if ((error = config_level_to_sysdir(va_arg(ap, int))) >= 0) {
git_buf *out = va_arg(ap, git_buf *);
*(va_arg(ap, size_t *)) = git_indexer__max_objects;
break;
+ case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
+ git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
+ break;
+
+ case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
+ git_http__expect_continue = (va_arg(ap, int) != 0);
+ break;
+
default:
git_error_set(GIT_ERROR_INVALID, "invalid option key");
error = -1;
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "sha1_lookup.h"
-
-#include <stdio.h>
-
-#include "oid.h"
-
-int sha1_position(const void *table,
- size_t stride,
- unsigned lo, unsigned hi,
- const unsigned char *key)
-{
- const unsigned char *base = table;
-
- while (lo < hi) {
- unsigned mi = (lo + hi) / 2;
- int cmp = git_oid__hashcmp(base + mi * stride, key);
-
- if (!cmp)
- return mi;
-
- if (cmp > 0)
- hi = mi;
- else
- lo = mi+1;
- }
-
- return -((int)lo)-1;
-}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_sha1_lookup_h__
-#define INCLUDE_sha1_lookup_h__
-
-#include "common.h"
-
-#include <stdlib.h>
-
-int sha1_position(const void *table,
- size_t stride,
- unsigned lo, unsigned hi,
- const unsigned char *key);
-
-#endif
sc = git__calloc(1, alloclen);
GIT_ERROR_CHECK_ALLOC(sc);
- git_pool_init(&sc->pool, 1);
-
- if (git_vector_init(&sc->items, 4, item_cmp) < 0 ||
- git_strmap_alloc(&sc->map) < 0)
+ if (git_pool_init(&sc->pool, 1) < 0 ||
+ git_vector_init(&sc->items, 4, item_cmp) < 0 ||
+ git_strmap_new(&sc->map) < 0)
goto fail;
if (git_rwlock_init(&sc->lock)) {
/* find and/or insert item, returning pointer to item data */
int git_sortedcache_upsert(void **out, git_sortedcache *sc, const char *key)
{
- size_t pos;
- int error = 0;
- void *item;
size_t keylen, itemlen;
+ int error = 0;
char *item_key;
+ void *item;
- pos = git_strmap_lookup_index(sc->map, key);
- if (git_strmap_valid_index(sc->map, pos)) {
- item = git_strmap_value_at(sc->map, pos);
+ if ((item = git_strmap_get(sc->map, key)) != NULL)
goto done;
- }
keylen = strlen(key);
itemlen = sc->item_path_offset + keylen + 1;
itemlen = (itemlen + 7) & ~7;
- if ((item = git_pool_mallocz(&sc->pool, (uint32_t)itemlen)) == NULL) {
+ if ((item = git_pool_mallocz(&sc->pool, itemlen)) == NULL) {
/* don't use GIT_ERROR_CHECK_ALLOC b/c of lock */
error = -1;
goto done;
item_key = ((char *)item) + sc->item_path_offset;
memcpy(item_key, key, keylen);
- pos = git_strmap_put(sc->map, item_key, &error);
- if (error < 0)
+ if ((error = git_strmap_set(sc->map, item_key, item)) < 0)
goto done;
- if (!error)
- git_strmap_set_key_at(sc->map, pos, item_key);
- git_strmap_set_value_at(sc->map, pos, item);
-
- error = git_vector_insert(&sc->items, item);
- if (error < 0)
- git_strmap_delete_at(sc->map, pos);
+ if ((error = git_vector_insert(&sc->items, item)) < 0)
+ git_strmap_delete(sc->map, item_key);
done:
if (out)
/* lookup item by key */
void *git_sortedcache_lookup(const git_sortedcache *sc, const char *key)
{
- size_t pos = git_strmap_lookup_index(sc->map, key);
- if (git_strmap_valid_index(sc->map, pos))
- return git_strmap_value_at(sc->map, pos);
- return NULL;
+ return git_strmap_get(sc->map, key);
}
/* find out how many items are in the cache */
int git_sortedcache_remove(git_sortedcache *sc, size_t pos)
{
char *item;
- size_t mappos;
- /* because of pool allocation, this can't actually remove the item,
+ /*
+ * Because of pool allocation, this can't actually remove the item,
* but we can remove it from the items vector and the hash table.
*/
(void)git_vector_remove(&sc->items, pos);
- mappos = git_strmap_lookup_index(sc->map, item + sc->item_path_offset);
- git_strmap_delete_at(sc->map, mappos);
+ git_strmap_delete(sc->map, item + sc->item_path_offset);
if (sc->free_item)
sc->free_item(sc->free_item_payload, item);
#include "common.h"
#include "util.h"
-#include "fileops.h"
+#include "futils.h"
#include "vector.h"
#include "thread-utils.h"
#include "pool.h"
git_index *index,
const char *path)
{
- git_index *repo_index;
+ git_index *repo_index = NULL;
git_index_entry entry = {{0}};
struct stat st;
int error;
return error;
git_index_entry__init_from_stat(&entry, &st,
- (repo_index != NULL || !repo_index->distrust_filemode));
+ (repo_index == NULL || !repo_index->distrust_filemode));
entry.path = path;
git_commit *b_commit,
git_commit *u_commit)
{
- int error = 0;
- git_tree *w_tree = NULL, *i_tree = NULL;
- git_index *i_index = NULL;
- const git_commit *parents[] = { NULL, NULL, NULL };
- int ignorecase;
+ const git_commit *parents[] = { NULL, NULL, NULL };
+ git_index *i_index = NULL, *r_index = NULL;
+ git_tree *w_tree = NULL;
+ int error = 0, ignorecase;
parents[0] = b_commit;
parents[1] = i_commit;
parents[2] = u_commit;
- if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
- goto cleanup;
-
- if ((error = git_index_new(&i_index)) < 0 ||
- (error = git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE)) < 0)
+ if ((error = git_repository_index(&r_index, repo) < 0) ||
+ (error = git_index_new(&i_index)) < 0 ||
+ (error = git_index__fill(i_index, &r_index->entries) < 0) ||
+ (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
goto cleanup;
git_index__set_ignore_case(i_index, ignorecase);
- if ((error = git_index_read_tree(i_index, i_tree)) < 0)
- goto cleanup;
-
if ((error = build_workdir_tree(&w_tree, repo, i_index, b_commit)) < 0)
goto cleanup;
parents);
cleanup:
- git_tree_free(i_tree);
git_tree_free(w_tree);
git_index_free(i_index);
+ git_index_free(r_index);
return error;
}
-static int prepare_worktree_commit_message(
- git_buf* msg,
- const char *user_message)
+static int prepare_worktree_commit_message(git_buf *out, const char *user_message)
{
git_buf buf = GIT_BUF_INIT;
- int error;
-
- if ((error = git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg))) < 0)
- return error;
-
- git_buf_clear(msg);
+ int error = 0;
- if (!user_message)
- git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf));
- else {
+ if (!user_message) {
+ git_buf_printf(&buf, "WIP on %s", git_buf_cstr(out));
+ } else {
const char *colon;
- if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL)
+ if ((colon = strchr(git_buf_cstr(out), ':')) == NULL)
goto cleanup;
- git_buf_puts(msg, "On ");
- git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr);
- git_buf_printf(msg, ": %s\n", user_message);
+ git_buf_puts(&buf, "On ");
+ git_buf_put(&buf, git_buf_cstr(out), colon - out->ptr);
+ git_buf_printf(&buf, ": %s\n", user_message);
}
- error = (git_buf_oom(msg) || git_buf_oom(&buf)) ? -1 : 0;
+ if (git_buf_oom(&buf)) {
+ error = -1;
+ goto cleanup;
+ }
+
+ git_buf_swap(out, &buf);
cleanup:
git_buf_dispose(&buf);
-
return error;
}
return GIT_PASSTHROUGH;
}
-static int ensure_there_are_changes_to_stash(
- git_repository *repo,
- bool include_untracked_files,
- bool include_ignored_files)
+static int ensure_there_are_changes_to_stash(git_repository *repo, uint32_t flags)
{
int error;
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
- if (include_untracked_files)
+ if (flags & GIT_STASH_INCLUDE_UNTRACKED)
opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED |
GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
- if (include_ignored_files)
+ if (flags & GIT_STASH_INCLUDE_IGNORED)
opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED |
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
return error;
}
-static int reset_index_and_workdir(
- git_repository *repo,
- git_commit *commit,
- bool remove_untracked,
- bool remove_ignored)
+static int reset_index_and_workdir(git_repository *repo, git_commit *commit, uint32_t flags)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
-
- if (remove_untracked)
+ if (flags & GIT_STASH_INCLUDE_UNTRACKED)
opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;
-
- if (remove_ignored)
+ if (flags & GIT_STASH_INCLUDE_IGNORED)
opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_IGNORED;
return git_checkout_tree(repo, (git_object *)commit, &opts);
if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0)
goto cleanup;
- if ((error = ensure_there_are_changes_to_stash(
- repo,
- (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
- (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
+ if ((error = ensure_there_are_changes_to_stash(repo, flags)) < 0)
goto cleanup;
if ((error = git_repository_index(&index, repo)) < 0)
goto cleanup;
- if ((error = commit_index(
- &i_commit, repo, index, stasher, git_buf_cstr(&msg), b_commit)) < 0)
+ if ((error = commit_index(&i_commit, repo, index, stasher,
+ git_buf_cstr(&msg), b_commit)) < 0)
goto cleanup;
if ((flags & (GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)) &&
- (error = commit_untracked(
- &u_commit, repo, stasher, git_buf_cstr(&msg),
- i_commit, flags)) < 0)
+ (error = commit_untracked(&u_commit, repo, stasher,
+ git_buf_cstr(&msg), i_commit, flags)) < 0)
goto cleanup;
if ((error = prepare_worktree_commit_message(&msg, message)) < 0)
goto cleanup;
- if ((error = commit_worktree(
- out, repo, stasher, git_buf_cstr(&msg),
- i_commit, b_commit, u_commit)) < 0)
+ if ((error = commit_worktree(out, repo, stasher, git_buf_cstr(&msg),
+ i_commit, b_commit, u_commit)) < 0)
goto cleanup;
git_buf_rtrim(&msg);
if ((error = update_reflog(out, repo, git_buf_cstr(&msg))) < 0)
goto cleanup;
- if ((error = reset_index_and_workdir(
- repo,
- ((flags & GIT_STASH_KEEP_INDEX) != 0) ? i_commit : b_commit,
- (flags & GIT_STASH_INCLUDE_UNTRACKED) != 0,
- (flags & GIT_STASH_INCLUDE_IGNORED) != 0)) < 0)
+ if ((error = reset_index_and_workdir(repo, (flags & GIT_STASH_KEEP_INDEX) ? i_commit : b_commit,
+ flags)) < 0)
goto cleanup;
cleanup:
opts->checkout_options.their_label = "Stashed changes";
}
-int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version)
+int git_stash_apply_options_init(git_stash_apply_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_stash_apply_options, GIT_STASH_APPLY_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version)
+{
+ return git_stash_apply_options_init(opts, version);
+}
+#endif
+
#define NOTIFY_PROGRESS(opts, progress_type) \
do { \
if ((opts).progress_cb && \
#include "status.h"
#include "git2.h"
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "vector.h"
#include "tree.h"
#include "repository.h"
#include "ignore.h"
#include "index.h"
+#include "wildmatch.h"
#include "git2/diff.h"
#include "diff.h"
/* if OIDs don't match, we might need to calculate them now to
* discern between RENAMED vs RENAMED+MODIFED
*/
- if (git_oid_iszero(&idx2wd->old_file.id) &&
- diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
+ if (git_oid_is_zero(&idx2wd->old_file.id) &&
+ diff->old_src == GIT_ITERATOR_WORKDIR &&
!git_diff__oid_for_file(
&idx2wd->old_file.id, diff, idx2wd->old_file.path,
idx2wd->old_file.mode, idx2wd->old_file.size))
idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
- if (git_oid_iszero(&idx2wd->new_file.id) &&
- diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
+ if (git_oid_is_zero(&idx2wd->new_file.id) &&
+ diff->new_src == GIT_ITERATOR_WORKDIR &&
!git_diff__oid_for_file(
&idx2wd->new_file.id, diff, idx2wd->new_file.path,
idx2wd->new_file.mode, idx2wd->new_file.size))
if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 ||
(error = git_repository_index(&index, repo)) < 0)
return error;
-
+
if (opts != NULL && opts->baseline != NULL) {
head = opts->baseline;
} else {
char *expected;
unsigned int count;
unsigned int status;
- int fnm_flags;
+ int wildmatch_flags;
int ambiguous;
};
sfi->count++;
sfi->status = status;
- strcomp = (sfi->fnm_flags & FNM_CASEFOLD) ? git__strcasecmp : git__strcmp;
+ strcomp = (sfi->wildmatch_flags & WM_CASEFOLD) ? git__strcasecmp : git__strcmp;
if (sfi->count > 1 ||
(strcomp(sfi->expected, path) != 0 &&
- p_fnmatch(sfi->expected, path, sfi->fnm_flags) != 0))
+ wildmatch(sfi->expected, path, sfi->wildmatch_flags) != 0))
{
sfi->ambiguous = true;
return GIT_EAMBIGUOUS; /* git_error_set will be done by caller */
if ((sfi.expected = git__strdup(path)) == NULL)
return -1;
if (index->ignore_case)
- sfi.fnm_flags = FNM_CASEFOLD;
+ sfi.wildmatch_flags = WM_CASEFOLD;
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
return git_ignore_path_is_ignored(ignored, repo, path);
}
-int git_status_init_options(git_status_options *opts, unsigned int version)
+int git_status_options_init(git_status_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_status_options, GIT_STATUS_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_status_init_options(git_status_options *opts, unsigned int version)
+{
+ return git_status_options_init(opts, version);
+}
+#endif
+
int git_status_list_get_perfdata(
git_diff_perfdata *out, const git_status_list *status)
{
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "stdalloc.h"
-
-static void *stdalloc__malloc(size_t len, const char *file, int line)
-{
- void *ptr = malloc(len);
-
- GIT_UNUSED(file);
- GIT_UNUSED(line);
-
- if (!ptr) git_error_set_oom();
- return ptr;
-}
-
-static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line)
-{
- void *ptr = calloc(nelem, elsize);
-
- GIT_UNUSED(file);
- GIT_UNUSED(line);
-
- if (!ptr) git_error_set_oom();
- return ptr;
-}
-
-static char *stdalloc__strdup(const char *str, const char *file, int line)
-{
- char *ptr = strdup(str);
-
- GIT_UNUSED(file);
- GIT_UNUSED(line);
-
- if (!ptr) git_error_set_oom();
- return ptr;
-}
-
-static char *stdalloc__strndup(const char *str, size_t n, const char *file, int line)
-{
- size_t length = 0, alloclength;
- char *ptr;
-
- length = p_strnlen(str, n);
-
- if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
- !(ptr = stdalloc__malloc(alloclength, file, line)))
- return NULL;
-
- if (length)
- memcpy(ptr, str, length);
-
- ptr[length] = '\0';
-
- return ptr;
-}
-
-static char *stdalloc__substrdup(const char *start, size_t n, const char *file, int line)
-{
- char *ptr;
- size_t alloclen;
-
- if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
- !(ptr = stdalloc__malloc(alloclen, file, line)))
- return NULL;
-
- memcpy(ptr, start, n);
- ptr[n] = '\0';
- return ptr;
-}
-
-static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line)
-{
- void *new_ptr = realloc(ptr, size);
-
- GIT_UNUSED(file);
- GIT_UNUSED(line);
-
- if (!new_ptr) git_error_set_oom();
- return new_ptr;
-}
-
-static void *stdalloc__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
-{
- size_t newsize;
-
- GIT_UNUSED(file);
- GIT_UNUSED(line);
-
- return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
- NULL : realloc(ptr, newsize);
-}
-
-static void *stdalloc__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
-{
- return stdalloc__reallocarray(NULL, nelem, elsize, file, line);
-}
-
-static void stdalloc__free(void *ptr)
-{
- free(ptr);
-}
-
-int git_stdalloc_init_allocator(git_allocator *allocator)
-{
- allocator->gmalloc = stdalloc__malloc;
- allocator->gcalloc = stdalloc__calloc;
- allocator->gstrdup = stdalloc__strdup;
- allocator->gstrndup = stdalloc__strndup;
- allocator->gsubstrdup = stdalloc__substrdup;
- allocator->grealloc = stdalloc__realloc;
- allocator->greallocarray = stdalloc__reallocarray;
- allocator->gmallocarray = stdalloc__mallocarray;
- allocator->gfree = stdalloc__free;
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#ifndef INCLUDE_stdalloc_h__
-#define INCLUDE_stdalloc_h__
-
-#include "alloc.h"
-
-#include "common.h"
-
-int git_stdalloc_init_allocator(git_allocator *allocator);
-
-#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "util.h"
+
+#include "common.h"
+
+int git_strarray_copy(git_strarray *tgt, const git_strarray *src)
+{
+ size_t i;
+
+ assert(tgt && src);
+
+ memset(tgt, 0, sizeof(*tgt));
+
+ if (!src->count)
+ return 0;
+
+ tgt->strings = git__calloc(src->count, sizeof(char *));
+ GIT_ERROR_CHECK_ALLOC(tgt->strings);
+
+ for (i = 0; i < src->count; ++i) {
+ if (!src->strings[i])
+ continue;
+
+ tgt->strings[tgt->count] = git__strdup(src->strings[i]);
+ if (!tgt->strings[tgt->count]) {
+ git_strarray_dispose(tgt);
+ memset(tgt, 0, sizeof(*tgt));
+ return -1;
+ }
+
+ tgt->count++;
+ }
+
+ return 0;
+}
+
+void git_strarray_dispose(git_strarray *array)
+{
+ size_t i;
+
+ if (array == NULL)
+ return;
+
+ for (i = 0; i < array->count; ++i)
+ git__free(array->strings[i]);
+
+ git__free(array->strings);
+
+ memset(array, 0, sizeof(*array));
+}
+
+#ifndef GIT_DEPRECATE_HARD
+void git_strarray_free(git_strarray *array)
+{
+ git_strarray_dispose(array);
+}
+#endif
lock = mode & CRYPTO_LOCK;
if (lock) {
- git_mutex_lock(&openssl_locks[n]);
+ (void)git_mutex_lock(&openssl_locks[n]);
} else {
git_mutex_unlock(&openssl_locks[n]);
}
}
}
+#ifdef VALGRIND
+#ifdef OPENSSL_LEGACY_API
+static void *git_openssl_malloc(size_t bytes)
+{
+ return git__calloc(1, bytes);
+}
+
+static void *git_openssl_realloc(void *mem, size_t size)
+{
+ return git__realloc(mem, size);
+}
+
+static void git_openssl_free(void *mem)
+{
+ return git__free(mem);
+}
+#else
+static void *git_openssl_malloc(size_t bytes, const char *file, int line)
+{
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+ return git__calloc(1, bytes);
+}
+
+static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line)
+{
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+ return git__realloc(mem, size);
+}
+
+static void git_openssl_free(void *mem, const char *file, int line)
+{
+ GIT_UNUSED(file);
+ GIT_UNUSED(line);
+ return git__free(mem);
+}
+#endif
+#endif
+
int git_openssl_stream_global_init(void)
{
long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
const char *ciphers = git_libgit2__ssl_ciphers();
+#ifdef VALGRIND
+ static bool allocators_initialized = false;
+#endif
/* Older OpenSSL and MacOS OpenSSL doesn't have this */
#ifdef SSL_OP_NO_COMPRESSION
ssl_opts |= SSL_OP_NO_COMPRESSION;
#endif
+#ifdef VALGRIND
+ /* Swap in our own allocator functions that initialize allocated memory */
+ if (!allocators_initialized &&
+ CRYPTO_set_mem_functions(git_openssl_malloc,
+ git_openssl_realloc,
+ git_openssl_free) != 1)
+ goto error;
+ allocators_initialized = true;
+#endif
+
OPENSSL_init_ssl(0, NULL);
/*
static int bio_write(BIO *b, const char *buf, int len)
{
git_stream *io = (git_stream *) BIO_get_data(b);
-
return (int) git_stream_write(io, buf, len, 0);
}
static int openssl_certificate(git_cert **out, git_stream *stream)
{
openssl_stream *st = (openssl_stream *) stream;
- int len;
X509 *cert = SSL_get_peer_certificate(st->ssl);
- unsigned char *guard, *encoded_cert;
+ unsigned char *guard, *encoded_cert = NULL;
+ int error, len;
/* Retrieve the length of the certificate first */
len = i2d_X509(cert, NULL);
if (len < 0) {
git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information");
- return -1;
+ error = -1;
+ goto out;
}
encoded_cert = git__malloc(len);
len = i2d_X509(cert, &guard);
if (len < 0) {
- git__free(encoded_cert);
git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information");
- return -1;
+ error = -1;
+ goto out;
}
st->cert_info.parent.cert_type = GIT_CERT_X509;
st->cert_info.data = encoded_cert;
st->cert_info.len = len;
+ encoded_cert = NULL;
*out = &st->cert_info.parent;
+ error = 0;
- return 0;
+out:
+ git__free(encoded_cert);
+ X509_free(cert);
+ return error;
}
static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2/errors.h"
-
#include "common.h"
+
+#include "streams/registry.h"
+
#include "global.h"
#include "streams/tls.h"
#include "streams/mbedtls.h"
return 0;
}
-
+#ifndef GIT_DEPRECATE_HARD
int git_stream_register_tls(
int GIT_CALLBACK(ctor)(git_stream **out, const char *host, const char *port))
{
return git_stream_register(GIT_STREAM_TLS, NULL);
}
}
+#endif
errno = 0;
if ((written = p_send(st->s, data, len, flags)) < 0) {
- net_set_error("Error sending data");
+ net_set_error("error sending data");
return -1;
}
git_socket_stream *st = (git_socket_stream *) stream;
if ((ret = p_recv(st->s, data, len, 0)) < 0)
- net_set_error("Error receiving socket data");
+ net_set_error("error receiving socket data");
return ret;
}
__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal)
-int git_strmap_alloc(git_strmap **map)
+int git_strmap_new(git_strmap **out)
{
- if ((*map = kh_init(str)) == NULL) {
- git_error_set_oom();
- return -1;
- }
+ *out = kh_init(str);
+ GIT_ERROR_CHECK_ALLOC(*out);
return 0;
}
kh_clear(str, map);
}
-size_t git_strmap_num_entries(git_strmap *map)
+size_t git_strmap_size(git_strmap *map)
{
return kh_size(map);
}
-size_t git_strmap_lookup_index(git_strmap *map, const char *key)
-{
- return kh_get(str, map, key);
-}
-
-int git_strmap_valid_index(git_strmap *map, size_t idx)
-{
- return idx != kh_end(map);
-}
-
-int git_strmap_exists(git_strmap *map, const char *key)
-{
- return kh_get(str, map, key) != kh_end(map);
-}
-
-int git_strmap_has_data(git_strmap *map, size_t idx)
-{
- return kh_exist(map, idx);
-}
-
-const char *git_strmap_key(git_strmap *map, size_t idx)
-{
- return kh_key(map, idx);
-}
-
-void git_strmap_set_key_at(git_strmap *map, size_t idx, char *key)
-{
- kh_val(map, idx) = key;
-}
-
-void *git_strmap_value_at(git_strmap *map, size_t idx)
+void *git_strmap_get(git_strmap *map, const char *key)
{
+ size_t idx = kh_get(str, map, key);
+ if (idx == kh_end(map) || !kh_exist(map, idx))
+ return NULL;
return kh_val(map, idx);
}
-void git_strmap_set_value_at(git_strmap *map, size_t idx, void *value)
-{
- kh_val(map, idx) = value;
-}
-
-void git_strmap_delete_at(git_strmap *map, size_t idx)
+int git_strmap_set(git_strmap *map, const char *key, void *value)
{
- kh_del(str, map, idx);
-}
+ size_t idx;
+ int rval;
-int git_strmap_put(git_strmap *map, const char *key, int *err)
-{
- return kh_put(str, map, key, err);
-}
+ idx = kh_put(str, map, key, &rval);
+ if (rval < 0)
+ return -1;
-void git_strmap_insert(git_strmap *map, const char *key, void *value, int *rval)
-{
- khiter_t idx = kh_put(str, map, key, rval);
+ if (rval == 0)
+ kh_key(map, idx) = key;
- if ((*rval) >= 0) {
- if ((*rval) == 0)
- kh_key(map, idx) = key;
- kh_val(map, idx) = value;
- }
-}
+ kh_val(map, idx) = value;
-void git_strmap_delete(git_strmap *map, const char *key)
-{
- khiter_t idx = git_strmap_lookup_index(map, key);
- if (git_strmap_valid_index(map, idx))
- git_strmap_delete_at(map, idx);
+ return 0;
}
-size_t git_strmap_begin(git_strmap *map)
+int git_strmap_delete(git_strmap *map, const char *key)
{
- GIT_UNUSED(map);
+ khiter_t idx = kh_get(str, map, key);
+ if (idx == kh_end(map))
+ return GIT_ENOTFOUND;
+ kh_del(str, map, idx);
return 0;
}
-size_t git_strmap_end(git_strmap *map)
+int git_strmap_exists(git_strmap *map, const char *key)
{
- return map->n_buckets;
+ return kh_get(str, map, key) != kh_end(map);
}
-int git_strmap_next(
- void **data,
- size_t* iter,
- git_strmap *map)
+int git_strmap_iterate(void **value, git_strmap *map, size_t *iter, const char **key)
{
- if (!map)
- return GIT_ERROR;
+ size_t i = *iter;
- while (*iter != git_strmap_end(map)) {
- if (!(git_strmap_has_data(map, *iter))) {
- ++(*iter);
- continue;
- }
+ while (i < map->n_buckets && !kh_exist(map, i))
+ i++;
- *data = git_strmap_value_at(map, *iter);
+ if (i >= map->n_buckets)
+ return GIT_ITEROVER;
- ++(*iter);
+ if (key)
+ *key = kh_key(map, i);
+ if (value)
+ *value = kh_val(map, i);
+ *iter = ++i;
- return GIT_OK;
- }
-
- return GIT_ITEROVER;
+ return 0;
}
#include "common.h"
+/** A map with C strings as key. */
typedef struct kh_str_s git_strmap;
-int git_strmap_alloc(git_strmap **map);
+/**
+ * Allocate a new string map.
+ *
+ * @param out Pointer to the map that shall be allocated.
+ * @return 0 on success, an error code if allocation has failed.
+ */
+int git_strmap_new(git_strmap **out);
+
+/**
+ * Free memory associated with the map.
+ *
+ * Note that this function will _not_ free keys or values added
+ * to this map.
+ *
+ * @param map Pointer to the map that is to be free'd. May be
+ * `NULL`.
+ */
void git_strmap_free(git_strmap *map);
+
+/**
+ * Clear all entries from the map.
+ *
+ * This function will remove all entries from the associated map.
+ * Memory associated with it will not be released, though.
+ *
+ * @param map Pointer to the map that shall be cleared. May be
+ * `NULL`.
+ */
void git_strmap_clear(git_strmap *map);
-size_t git_strmap_num_entries(git_strmap *map);
+/**
+ * Return the number of elements in the map.
+ *
+ * @parameter map map containing the elements
+ * @return number of elements in the map
+ */
+size_t git_strmap_size(git_strmap *map);
-size_t git_strmap_lookup_index(git_strmap *map, const char *key);
-int git_strmap_valid_index(git_strmap *map, size_t idx);
+/**
+ * Return value associated with the given key.
+ *
+ * @param map map to search key in
+ * @param key key to search for
+ * @return value associated with the given key or NULL if the key was not found
+ */
+void *git_strmap_get(git_strmap *map, const char *key);
+/**
+ * Set the entry for key to value.
+ *
+ * If the map has no corresponding entry for the given key, a new
+ * entry will be created with the given value. If an entry exists
+ * already, its value will be updated to match the given value.
+ *
+ * @param map map to create new entry in
+ * @param key key to set
+ * @param value value to associate the key with; may be NULL
+ * @return zero if the key was successfully set, a negative error
+ * code otherwise
+ */
+int git_strmap_set(git_strmap *map, const char *key, void *value);
+
+/**
+ * Delete an entry from the map.
+ *
+ * Delete the given key and its value from the map. If no such
+ * key exists, this will do nothing.
+ *
+ * @param map map to delete key in
+ * @param key key to delete
+ * @return `0` if the key has been deleted, GIT_ENOTFOUND if no
+ * such key was found, a negative code in case of an
+ * error
+ */
+int git_strmap_delete(git_strmap *map, const char *key);
+
+/**
+ * Check whether a key exists in the given map.
+ *
+ * @param map map to query for the key
+ * @param key key to search for
+ * @return 0 if the key has not been found, 1 otherwise
+ */
int git_strmap_exists(git_strmap *map, const char *key);
-int git_strmap_has_data(git_strmap *map, size_t idx);
-
-const char *git_strmap_key(git_strmap *map, size_t idx);
-void git_strmap_set_key_at(git_strmap *map, size_t idx, char *key);
-void *git_strmap_value_at(git_strmap *map, size_t idx);
-void git_strmap_set_value_at(git_strmap *map, size_t idx, void *value);
-void git_strmap_delete_at(git_strmap *map, size_t idx);
-
-int git_strmap_put(git_strmap *map, const char *key, int *err);
-void git_strmap_insert(git_strmap *map, const char *key, void *value, int *rval);
-void git_strmap_delete(git_strmap *map, const char *key);
-
-#define git_strmap_foreach(h, kvar, vvar, code) { size_t __i; \
- for (__i = git_strmap_begin(h); __i != git_strmap_end(h); ++__i) { \
- if (!git_strmap_has_data(h,__i)) continue; \
- (kvar) = git_strmap_key(h,__i); \
- (vvar) = git_strmap_value_at(h,__i); \
+
+/**
+ * Iterate over entries of the map.
+ *
+ * This functions allows to iterate over all key-value entries of
+ * the map. The current position is stored in the `iter` variable
+ * and should be initialized to `0` before the first call to this
+ * function.
+ *
+ * @param map map to iterate over
+ * @param value pointer to the variable where to store the current
+ * value. May be NULL.
+ * @param iter iterator storing the current position. Initialize
+ * with zero previous to the first call.
+ * @param key pointer to the variable where to store the current
+ * key. May be NULL.
+ * @return `0` if the next entry was correctly retrieved.
+ * GIT_ITEROVER if no entries are left. A negative error
+ * code otherwise.
+ */
+int git_strmap_iterate(void **value, git_strmap *map, size_t *iter, const char **key);
+
+#define git_strmap_foreach(h, kvar, vvar, code) { size_t __i = 0; \
+ while (git_strmap_iterate((void **) &(vvar), h, &__i, &(kvar)) == 0) { \
code; \
} }
-#define git_strmap_foreach_value(h, vvar, code) { size_t __i; \
- for (__i = git_strmap_begin(h); __i != git_strmap_end(h); ++__i) { \
- if (!git_strmap_has_data(h,__i)) continue; \
- (vvar) = git_strmap_value_at(h,__i); \
+#define git_strmap_foreach_value(h, vvar, code) { size_t __i = 0; \
+ while (git_strmap_iterate((void **) &(vvar), h, &__i, NULL) == 0) { \
code; \
} }
-size_t git_strmap_begin(git_strmap *map);
-size_t git_strmap_end(git_strmap *map);
-
-int git_strmap_next(
- void **data,
- size_t *iter,
- git_strmap *map);
-
#endif
#include "path.h"
#include "index.h"
#include "worktree.h"
+#include "clone.h"
#define GIT_MODULES_FILE ".gitmodules"
-static git_cvar_map _sm_update_map[] = {
- {GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
- {GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
- {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
- {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
- {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
- {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
+static git_configmap _sm_update_map[] = {
+ {GIT_CONFIGMAP_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
+ {GIT_CONFIGMAP_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
+ {GIT_CONFIGMAP_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
+ {GIT_CONFIGMAP_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
};
-static git_cvar_map _sm_ignore_map[] = {
- {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
- {GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
- {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
- {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
- {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
- {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
+static git_configmap _sm_ignore_map[] = {
+ {GIT_CONFIGMAP_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
+ {GIT_CONFIGMAP_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
+ {GIT_CONFIGMAP_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
+ {GIT_CONFIGMAP_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
};
-static git_cvar_map _sm_recurse_map[] = {
- {GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
- {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
- {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
+static git_configmap _sm_recurse_map[] = {
+ {GIT_CONFIGMAP_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
+ {GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
+ {GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
};
enum {
git_config_entry *entry;
git_buf buf = GIT_BUF_INIT;
git_strmap *names;
- int rval, isvalid;
- int error = 0;
+ int isvalid, error;
*out = NULL;
- if ((error = git_strmap_alloc(&names)) < 0)
+ if ((error = git_strmap_new(&names)) < 0)
goto out;
if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
if (!isvalid)
continue;
- git_strmap_insert(names, git__strdup(entry->value), git_buf_detach(&buf), &rval);
- if (rval < 0) {
+ if ((error = git_strmap_set(names, git__strdup(entry->value), git_buf_detach(&buf))) < 0) {
git_error_set(GIT_ERROR_NOMEMORY, "error inserting submodule into hash table");
error = -1;
goto out;
}
if (repo->submodule_cache != NULL) {
- size_t pos = git_strmap_lookup_index(repo->submodule_cache, name);
- if (git_strmap_valid_index(repo->submodule_cache, pos)) {
+ if ((sm = git_strmap_get(repo->submodule_cache, name)) != NULL) {
if (out) {
- *out = git_strmap_value_at(repo->submodule_cache, pos);
+ *out = sm;
GIT_REFCOUNT_INC(*out);
}
return 0;
static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
{
- int error = 0;
- size_t pos;
git_submodule *sm = NULL;
+ int error;
- pos = git_strmap_lookup_index(map, name);
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
+ if ((sm = git_strmap_get(map, name)) != NULL)
goto done;
- }
/* if the submodule doesn't exist yet in the map, create it */
if ((error = submodule_alloc(&sm, repo, name)) < 0)
return error;
- pos = git_strmap_put(map, sm->name, &error);
- /* nobody can beat us to adding it */
- assert(error != 0);
- if (error < 0) {
+ if ((error = git_strmap_set(map, sm->name, sm)) < 0) {
git_submodule_free(sm);
return error;
}
- git_strmap_set_value_at(map, pos, sm);
-
done:
GIT_REFCOUNT_INC(sm);
*out = sm;
goto done;
while (!(error = git_iterator_advance(&entry, i))) {
- size_t pos = git_strmap_lookup_index(map, entry->path);
git_submodule *sm;
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
-
+ if ((sm = git_strmap_get(map, entry->path)) != NULL) {
if (S_ISGITLINK(entry->mode))
submodule_update_from_index_entry(sm, entry);
else
sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
} else if (S_ISGITLINK(entry->mode)) {
- size_t name_pos;
const char *name;
- name_pos = git_strmap_lookup_index(names, entry->path);
- if (git_strmap_valid_index(names, name_pos)) {
- name = git_strmap_value_at(names, name_pos);
- } else {
+ if ((name = git_strmap_get(names, entry->path)) == NULL)
name = entry->path;
- }
if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
submodule_update_from_index_entry(sm, entry);
goto done;
while (!(error = git_iterator_advance(&entry, i))) {
- size_t pos = git_strmap_lookup_index(map, entry->path);
git_submodule *sm;
- if (git_strmap_valid_index(map, pos)) {
- sm = git_strmap_value_at(map, pos);
-
+ if ((sm = git_strmap_get(map, entry->path)) != NULL) {
if (S_ISGITLINK(entry->mode))
submodule_update_from_head_data(sm, entry->mode, &entry->id);
else
sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
} else if (S_ISGITLINK(entry->mode)) {
- size_t name_pos;
const char *name;
- name_pos = git_strmap_lookup_index(names, entry->path);
- if (git_strmap_valid_index(names, name_pos)) {
- name = git_strmap_value_at(names, name_pos);
- } else {
+ if ((name = git_strmap_get(names, entry->path)) == NULL)
name = entry->path;
- }
if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
submodule_update_from_head_data(
return -1;
}
- if ((error = git_strmap_alloc(&submodules)) < 0)
+ if ((error = git_strmap_new(&submodules)) < 0)
return error;
if ((error = git_submodule__map(repo, submodules)) < 0)
goto done;
if (!(error = git_vector_init(
- &snapshot, git_strmap_num_entries(submodules), submodule_cmp))) {
+ &snapshot, git_strmap_size(submodules), submodule_cmp))) {
git_strmap_foreach_value(submodules, sm, {
if ((error = git_vector_insert(&snapshot, sm)) < 0)
return error;
}
+static int clone_return_origin(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
+{
+ GIT_UNUSED(url);
+ GIT_UNUSED(payload);
+ return git_remote_lookup(out, repo, name);
+}
+
+static int clone_return_repo(git_repository **out, const char *path, int bare, void *payload)
+{
+ git_submodule *sm = payload;
+
+ GIT_UNUSED(path);
+ GIT_UNUSED(bare);
+ return git_submodule_open(out, sm);
+}
+
+int git_submodule_clone(git_repository **out, git_submodule *submodule, const git_submodule_update_options *given_opts)
+{
+ int error;
+ git_repository *clone;
+ git_buf rel_path = GIT_BUF_INIT;
+ git_submodule_update_options sub_opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
+ git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
+
+ assert(submodule);
+
+ if (given_opts)
+ memcpy(&sub_opts, given_opts, sizeof(sub_opts));
+
+ GIT_ERROR_CHECK_VERSION(&sub_opts, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
+
+ memcpy(&opts.checkout_opts, &sub_opts.checkout_opts, sizeof(sub_opts.checkout_opts));
+ memcpy(&opts.fetch_opts, &sub_opts.fetch_opts, sizeof(sub_opts.fetch_opts));
+ opts.repository_cb = clone_return_repo;
+ opts.repository_cb_payload = submodule;
+ opts.remote_cb = clone_return_origin;
+ opts.remote_cb_payload = submodule;
+
+ git_buf_puts(&rel_path, git_repository_workdir(git_submodule_owner(submodule)));
+ git_buf_joinpath(&rel_path, git_buf_cstr(&rel_path), git_submodule_path(submodule));
+
+ GIT_ERROR_CHECK_ALLOC_BUF(&rel_path);
+
+ error = git_clone__submodule(&clone, git_submodule_url(submodule), git_buf_cstr(&rel_path), &opts);
+ if (error < 0)
+ goto cleanup;
+
+ if (!out)
+ git_repository_free(clone);
+ else
+ *out = clone;
+
+cleanup:
+ git_buf_dispose(&rel_path);
+
+ return error;
+}
+
int git_submodule_add_finalize(git_submodule *sm)
{
int error;
return error;
}
-const char *git_submodule_update_to_str(git_submodule_update_t update)
+static const char *submodule_update_to_str(git_submodule_update_t update)
{
int i;
for (i = 0; i < (int)ARRAY_SIZE(_sm_update_map); ++i)
return error;
}
-static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
+static int write_mapped_var(git_repository *repo, const char *name, git_configmap *maps, size_t nmaps, const char *var, int ival)
{
- git_cvar_t type;
+ git_configmap_t type;
const char *val;
if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
return -1;
}
- if (type == GIT_CVAR_TRUE)
+ if (type == GIT_CONFIGMAP_TRUE)
val = "true";
return write_var(repo, name, var, val);
return submodule_repo_create(out, sm->repo, path);
}
-int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
+int git_submodule_update_options_init(git_submodule_update_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
+{
+ return git_submodule_update_options_init(opts, version);
+}
+#endif
+
int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
{
int error;
/* write "submodule.NAME.update" if not default */
val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
- NULL : git_submodule_update_to_str(sm->update);
+ NULL : submodule_update_to_str(sm->update);
if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
(error = git_config__update_entry(
int git_submodule_sync(git_submodule *sm)
{
- int error = 0;
- git_config *cfg = NULL;
- git_buf key = GIT_BUF_INIT;
+ git_buf key = GIT_BUF_INIT, url = GIT_BUF_INIT, remote_name = GIT_BUF_INIT;
git_repository *smrepo = NULL;
+ git_config *cfg = NULL;
+ int error = 0;
if (!sm->url) {
- git_error_set(GIT_ERROR_SUBMODULE,
- "no URL configured for submodule '%s'", sm->name);
+ git_error_set(GIT_ERROR_SUBMODULE, "no URL configured for submodule '%s'", sm->name);
return -1;
}
/* copy URL over to config only if it already exists */
+ if ((error = git_repository_config__weakptr(&cfg, sm->repo)) < 0 ||
+ (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
+ (error = git_submodule_resolve_url(&url, sm->repo, sm->url)) < 0 ||
+ (error = git_config__update_entry(cfg, key.ptr, url.ptr, true, true)) < 0)
+ goto out;
- if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
- !(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
- error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
+ if (!(sm->flags & GIT_SUBMODULE_STATUS_IN_WD))
+ goto out;
/* if submodule exists in the working directory, update remote url */
+ if ((error = git_submodule_open(&smrepo, sm)) < 0 ||
+ (error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
+ goto out;
- if (!error &&
- (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
- !(error = git_submodule_open(&smrepo, sm)))
- {
- git_buf remote_name = GIT_BUF_INIT;
-
- if ((error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
- /* return error from reading submodule config */;
- else if ((error = lookup_head_remote_key(&remote_name, smrepo)) < 0) {
- git_error_clear();
- error = git_buf_sets(&key, "remote.origin.url");
- } else {
- error = git_buf_join3(
- &key, '.', "remote", remote_name.ptr, "url");
- git_buf_dispose(&remote_name);
- }
-
- if (!error)
- error = git_config__update_entry(cfg, key.ptr, sm->url, true, false);
-
- git_repository_free(smrepo);
+ if (lookup_head_remote_key(&remote_name, smrepo) == 0) {
+ if ((error = git_buf_join3(&key, '.', "remote", remote_name.ptr, "url")) < 0)
+ goto out;
+ } else if ((error = git_buf_sets(&key, "remote.origin.url")) < 0) {
+ goto out;
}
- git_buf_dispose(&key);
+ if ((error = git_config__update_entry(cfg, key.ptr, url.ptr, true, false)) < 0)
+ goto out;
+out:
+ git_repository_free(smrepo);
+ git_buf_dispose(&remote_name);
+ git_buf_dispose(&key);
+ git_buf_dispose(&url);
return error;
}
int git_submodule_reload(git_submodule *sm, int force)
{
- int error = 0, isvalid;
- git_config *mods;
+ git_config *mods = NULL;
+ int error;
GIT_UNUSED(force);
assert(sm);
- isvalid = git_submodule_name_is_valid(sm->repo, sm->name, 0);
- if (isvalid <= 0) {
+ if ((error = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0)
/* This should come with a warning, but we've no API for that */
- return isvalid;
- }
+ goto out;
- if (!git_repository_is_bare(sm->repo)) {
- /* refresh config data */
- if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
- return error;
- if (mods != NULL) {
- error = submodule_read_config(sm, mods);
- git_config_free(mods);
+ if (git_repository_is_bare(sm->repo))
+ goto out;
- if (error < 0)
- return error;
- }
+ /* refresh config data */
+ if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
+ goto out;
- /* refresh wd data */
- sm->flags &=
- ~(GIT_SUBMODULE_STATUS_IN_WD |
- GIT_SUBMODULE_STATUS__WD_OID_VALID |
- GIT_SUBMODULE_STATUS__WD_FLAGS);
+ if (mods != NULL && (error = submodule_read_config(sm, mods)) < 0)
+ goto out;
- error = submodule_load_from_wd_lite(sm);
- }
+ /* refresh wd data */
+ sm->flags &=
+ ~(GIT_SUBMODULE_STATUS_IN_WD |
+ GIT_SUBMODULE_STATUS__WD_OID_VALID |
+ GIT_SUBMODULE_STATUS__WD_FLAGS);
- if (error == 0 && (error = submodule_update_index(sm)) == 0)
- error = submodule_update_head(sm);
+ if ((error = submodule_load_from_wd_lite(sm)) < 0 ||
+ (error = submodule_update_index(sm)) < 0 ||
+ (error = submodule_update_head(sm)) < 0)
+ goto out;
+out:
+ git_config_free(mods);
return error;
}
return 0;
}
-int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
+static int submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
{
int val;
if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
in_config = 1;
- if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
+ if ((error = submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
goto cleanup;
sm->fetch_recurse_default = sm->fetch_recurse;
} else if (error != GIT_ENOTFOUND) {
{
lfc_data *data = payload;
const char *namestart, *property;
- size_t pos;
git_strmap *map = data->map;
git_buf name = GIT_BUF_INIT;
git_submodule *sm;
* a new submodule, load the config and insert it. If it's
* already inserted, we've already loaded it, so we skip.
*/
- pos = git_strmap_lookup_index(map, name.ptr);
- if (git_strmap_valid_index(map, pos)) {
+ if (git_strmap_exists(map, name.ptr)) {
error = 0;
goto done;
}
goto done;
}
- git_strmap_insert(map, sm->name, sm, &error);
- assert(error != 0);
- if (error < 0)
+ if ((error = git_strmap_set(map, sm->name, sm)) < 0)
goto done;
error = 0;
int error = lookup_head_remote(remote, repo);
/* if that failed, use 'origin' instead */
- if (error == GIT_ENOTFOUND)
+ if (error == GIT_ENOTFOUND || error == GIT_EUNBORNBRANCH)
error = git_remote_lookup(remote, repo, "origin");
if (error == GIT_ENOTFOUND)
#include "git2/submodule.h"
#include "git2/repository.h"
-#include "fileops.h"
+#include "futils.h"
/* Notes:
*
#else
int error;
uid_t uid, euid;
+ const char *sandbox_id;
uid = getuid();
euid = geteuid();
+ /**
+ * If APP_SANDBOX_CONTAINER_ID is set, we are running in a
+ * sandboxed environment on macOS.
+ */
+ sandbox_id = getenv("APP_SANDBOX_CONTAINER_ID");
+
/*
* In case we are running setuid, use the configuration
* of the effective user.
+ *
+ * If we are running in a sandboxed environment on macOS,
+ * we have to get the HOME dir from the password entry file.
*/
- if (uid == euid)
+ if (!sandbox_id && uid == euid)
error = git__getenv(out, "HOME");
else
error = get_passwd_home(out, euid);
return 0;
}
-int git_sysdir_get_str(
- char *out,
- size_t outlen,
- git_sysdir_t which)
-{
- const git_buf *path = NULL;
-
- GIT_ERROR_CHECK_ERROR(git_sysdir_check_selector(which));
- GIT_ERROR_CHECK_ERROR(git_sysdir_get(&path, which));
-
- if (!out || path->size >= outlen) {
- git_error_set(GIT_ERROR_NOMEMORY, "buffer is too short for the path");
- return GIT_EBUFS;
- }
-
- git_buf_copy_cstr(out, outlen, path);
- return 0;
-}
-
#define PATH_MAGIC "$PATH"
int git_sysdir_set(git_sysdir_t which, const char *search_path)
}
done:
+ if (name)
+ git_error_set(GIT_ERROR_OS, "the %s file '%s' doesn't exist", label, name);
+ else
+ git_error_set(GIT_ERROR_OS, "the %s directory doesn't exist", label);
git_buf_dispose(path);
- git_error_set(GIT_ERROR_OS, "the %s file '%s' doesn't exist", label, name);
return GIT_ENOTFOUND;
}
*/
extern int git_sysdir_get(const git_buf **out, git_sysdir_t which);
-/**
- * Get search path into a preallocated buffer
- *
- * @param out String buffer to write into
- * @param outlen Size of string buffer
- * @param which Which search path to return
- * @return 0 on success, GIT_EBUFS if out is too small, <0 on other failure
- */
-
-extern int git_sysdir_get_str(char *out, size_t outlen, git_sysdir_t which);
-
/**
* Set search paths for global/system/xdg files
*
#include "commit.h"
#include "signature.h"
#include "message.h"
+#include "wildmatch.h"
#include "git2/object.h"
#include "git2/repository.h"
#include "git2/signature.h"
return git_tag_create__internal(oid, repo, tag_name, target, NULL, NULL, allow_ref_overwrite, 0);
}
-int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite)
+int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite)
{
git_tag tag;
int error;
GIT_UNUSED(oid);
if (!*filter->pattern ||
- p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0)
+ wildmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0)
{
char *matched = git__strdup(tag_name + GIT_REFS_TAGS_DIR_LEN);
GIT_ERROR_CHECK_ALLOC(matched);
{
return git_object_peel(tag_target, (const git_object *)tag, GIT_OBJECT_ANY);
}
+
+/* Deprecated Functions */
+
+#ifndef GIT_DEPRECATE_HARD
+int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite)
+{
+ return git_tag_create_from_buffer(oid, repo, buffer, allow_ref_overwrite);
+}
+#endif
#ifndef INCLUDE_thread_utils_h__
#define INCLUDE_thread_utils_h__
-#if defined(__GNUC__) && defined(GIT_THREADS)
+#if defined(GIT_THREADS)
+
+#if defined(__clang__)
+
+# if (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1))
+# error Atomic primitives do not exist on this version of clang; configure libgit2 with -DTHREADSAFE=OFF
+# else
+# define GIT_BUILTIN_ATOMIC
+# endif
+
+#elif defined(__GNUC__)
+
# if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
# error Atomic primitives do not exist on this version of gcc; configure libgit2 with -DTHREADSAFE=OFF
+# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+# define GIT_BUILTIN_ATOMIC
+# else
+# define GIT_BUILTIN_SYNC
# endif
+
#endif
+#endif /* GIT_THREADS */
+
/* Common operations even if threading has been disabled */
typedef struct {
#if defined(GIT_WIN32)
typedef struct {
#if defined(GIT_WIN32)
- __int64 val;
+ volatile __int64 val;
#else
- int64_t val;
+ volatile int64_t val;
#endif
} git_atomic64;
typedef git_atomic64 git_atomic_ssize;
+#define git_atomic_ssize_set git_atomic64_set
#define git_atomic_ssize_add git_atomic64_add
+#define git_atomic_ssize_get git_atomic64_get
#else
typedef git_atomic git_atomic_ssize;
+#define git_atomic_ssize_set git_atomic_set
#define git_atomic_ssize_add git_atomic_add
+#define git_atomic_ssize_get git_atomic_get
#endif
{
#if defined(GIT_WIN32)
InterlockedExchange(&a->val, (LONG)val);
-#elif defined(__GNUC__)
+#elif defined(GIT_BUILTIN_ATOMIC)
+ __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
__sync_lock_test_and_set(&a->val, val);
#else
# error "Unsupported architecture for atomic operations"
{
#if defined(GIT_WIN32)
return InterlockedIncrement(&a->val);
-#elif defined(__GNUC__)
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return __atomic_add_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
return __sync_add_and_fetch(&a->val, 1);
#else
# error "Unsupported architecture for atomic operations"
{
#if defined(GIT_WIN32)
return InterlockedExchangeAdd(&a->val, addend);
-#elif defined(__GNUC__)
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
return __sync_add_and_fetch(&a->val, addend);
#else
# error "Unsupported architecture for atomic operations"
{
#if defined(GIT_WIN32)
return InterlockedDecrement(&a->val);
-#elif defined(__GNUC__)
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return __atomic_sub_fetch(&a->val, 1, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
return __sync_sub_and_fetch(&a->val, 1);
#else
# error "Unsupported architecture for atomic operations"
#endif
}
+GIT_INLINE(int) git_atomic_get(git_atomic *a)
+{
+#if defined(GIT_WIN32)
+ return (int)InterlockedCompareExchange(&a->val, 0, 0);
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+ return __sync_val_compare_and_swap(&a->val, 0, 0);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+}
+
GIT_INLINE(void *) git___compare_and_swap(
void * volatile *ptr, void *oldval, void *newval)
{
- volatile void *foundval;
#if defined(GIT_WIN32)
+ volatile void *foundval;
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
-#elif defined(__GNUC__)
+ return (foundval == oldval) ? oldval : newval;
+#elif defined(GIT_BUILTIN_ATOMIC)
+ bool success = __atomic_compare_exchange(ptr, &oldval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ return success ? oldval : newval;
+#elif defined(GIT_BUILTIN_SYNC)
+ volatile void *foundval;
foundval = __sync_val_compare_and_swap(ptr, oldval, newval);
+ return (foundval == oldval) ? oldval : newval;
#else
# error "Unsupported architecture for atomic operations"
#endif
- return (foundval == oldval) ? oldval : newval;
}
GIT_INLINE(volatile void *) git___swap(
{
#if defined(GIT_WIN32)
return InterlockedExchangePointer(ptr, newval);
-#else
+#elif defined(GIT_BUILTIN_ATOMIC)
+ void * volatile foundval;
+ __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
+ return foundval;
+#elif defined(GIT_BUILTIN_SYNC)
return __sync_lock_test_and_set(ptr, newval);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+}
+
+GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
+{
+#if defined(GIT_WIN32)
+ void *newval = NULL, *oldval = NULL;
+ volatile void *foundval = NULL;
+ foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
+ return foundval;
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+ return (volatile void *)__sync_val_compare_and_swap(ptr, 0, 0);
+#else
+# error "Unsupported architecture for atomic operations"
#endif
}
{
#if defined(GIT_WIN32)
return InterlockedExchangeAdd64(&a->val, addend);
-#elif defined(__GNUC__)
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
return __sync_add_and_fetch(&a->val, addend);
#else
# error "Unsupported architecture for atomic operations"
#endif
}
+GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
+{
+#if defined(GIT_WIN32)
+ InterlockedExchange64(&a->val, val);
+#elif defined(GIT_BUILTIN_ATOMIC)
+ __atomic_store_n(&a->val, val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+ __sync_lock_test_and_set(&a->val, val);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+}
+
+GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
+{
+#if defined(GIT_WIN32)
+ return (int64_t)InterlockedCompareExchange64(&a->val, 0, 0);
+#elif defined(GIT_BUILTIN_ATOMIC)
+ return __atomic_load_n(&a->val, __ATOMIC_SEQ_CST);
+#elif defined(GIT_BUILTIN_SYNC)
+ return __sync_val_compare_and_swap(&a->val, 0, 0);
+#else
+# error "Unsupported architecture for atomic operations"
+#endif
+}
+
#endif
#else
return --a->val;
}
+GIT_INLINE(int) git_atomic_get(git_atomic *a)
+{
+ return (int)a->val;
+}
+
GIT_INLINE(void *) git___compare_and_swap(
void * volatile *ptr, void *oldval, void *newval)
{
return a->val;
}
-#endif
-
-#endif
+GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
+{
+ a->val = val;
+}
-GIT_INLINE(int) git_atomic_get(git_atomic *a)
+GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
{
- return (int)a->val;
+ return (int64_t)a->val;
}
+#endif
+
+#endif
+
/* Atomically replace oldval with newval
* @return oldval if it was replaced or newval if it was not
*/
#define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
+#define git__load(ptr) (void *)git___load((void * volatile *)&ptr)
+
extern int git_online_cpus(void);
-#if defined(GIT_THREADS) && defined(_MSC_VER)
-# define GIT_MEMORY_BARRIER MemoryBarrier()
-#elif defined(GIT_THREADS)
-# define GIT_MEMORY_BARRIER __sync_synchronize()
+#if defined(GIT_THREADS)
+
+# if defined(GIT_WIN32)
+# define GIT_MEMORY_BARRIER MemoryBarrier()
+# elif defined(GIT_BUILTIN_ATOMIC)
+# define GIT_MEMORY_BARRIER __atomic_thread_fence(__ATOMIC_SEQ_CST)
+# elif defined(GIT_BUILTIN_SYNC)
+# define GIT_MEMORY_BARRIER __sync_synchronize()
+# endif
+
#else
+
# define GIT_MEMORY_BARRIER /* noop */
+
#endif
#endif
#endif
-int git_trace_set(git_trace_level_t level, git_trace_callback callback)
+int git_trace_set(git_trace_level_t level, git_trace_cb callback)
{
#ifdef GIT_TRACE
assert(level == 0 || callback != NULL);
struct git_trace_data {
git_trace_level_t level;
- git_trace_callback callback;
+ git_trace_cb callback;
};
extern struct git_trace_data git_trace__data;
git_trace_level_t level,
const char *fmt, ...)
{
- git_trace_callback callback = git_trace__data.callback;
+ git_trace_cb callback = git_trace__data.callback;
git_buf message = GIT_BUF_INIT;
va_list ap;
GIT_UNUSED(fmt);
}
-#define git_trace_level() ((void)0)
+#define git_trace_level() ((git_trace_level_t)0)
#define git_trace git_trace__null
#endif
}
/*
- * Return the position of the start of the last line. If len is 0, return -1.
+ * Return the position of the start of the last line. If len is 0, return 0.
*/
-static int last_line(const char *buf, size_t len)
+static bool last_line(size_t *out, const char *buf, size_t len)
{
- int i;
+ size_t i;
+
+ *out = 0;
+
if (len == 0)
- return -1;
+ return false;
if (len == 1)
- return 0;
+ return true;
+
/*
* Skip the last character (in addition to the null terminator),
* because if the last character is a newline, it is considered as part
*/
i = len - 2;
- for (; i >= 0; i--) {
- if (buf[i] == '\n')
- return i + 1;
+ for (; i > 0; i--) {
+ if (buf[i] == '\n') {
+ *out = i + 1;
+ return true;
+ }
}
- return 0;
+ return true;
}
/*
* If the given line is of the form
- * "<token><optional whitespace><separator>..." or "<separator>...", return the
- * location of the separator. Otherwise, return -1. The optional whitespace
- * is allowed there primarily to allow things like "Bug #43" where <token> is
- * "Bug" and <separator> is "#".
+ * "<token><optional whitespace><separator>..." or "<separator>...", sets out
+ * to the location of the separator and returns true. Otherwise, returns
+ * false. The optional whitespace is allowed there primarily to allow things
+ * like "Bug #43" where <token> is "Bug" and <separator> is "#".
*
- * The separator-starts-line case (in which this function returns 0) is
- * distinguished from the non-well-formed-line case (in which this function
- * returns -1) because some callers of this function need such a distinction.
+ * The separator-starts-line case (in which this function returns true and
+ * sets out to 0) is distinguished from the non-well-formed-line case (in
+ * which this function returns false) because some callers of this function
+ * need such a distinction.
*/
-static int find_separator(const char *line, const char *separators)
+static bool find_separator(size_t *out, const char *line, const char *separators)
{
int whitespace_found = 0;
const char *c;
for (c = line; *c; c++) {
- if (strchr(separators, *c))
- return c - line;
+ if (strchr(separators, *c)) {
+ *out = c - line;
+ return true;
+ }
+
if (!whitespace_found && (isalnum(*c) || *c == '-'))
continue;
if (c != line && (*c == ' ' || *c == '\t')) {
}
break;
}
- return -1;
+ return false;
}
/*
* Returns the number of bytes from the tail to ignore, to be fed as
* the second parameter to append_signoff().
*/
-static int ignore_non_trailer(const char *buf, size_t len)
+static size_t ignore_non_trailer(const char *buf, size_t len)
{
- int boc = 0;
- size_t bol = 0;
+ size_t boc = 0, bol = 0;
int in_old_conflicts_block = 0;
size_t cutoff = len;
* Return the position of the start of the patch or the length of str if there
* is no patch in the message.
*/
-static int find_patch_start(const char *str)
+static size_t find_patch_start(const char *str)
{
const char *s;
* Return the position of the first trailer line or len if there are no
* trailers.
*/
-static int find_trailer_start(const char *buf, size_t len)
+static size_t find_trailer_start(const char *buf, size_t len)
{
const char *s;
- int end_of_title, l, only_spaces = 1;
+ size_t end_of_title, l;
+ int only_spaces = 1;
int recognized_prefix = 0, trailer_lines = 0, non_trailer_lines = 0;
/*
* Number of possible continuation lines encountered. This will be
* trailers, or (ii) contains at least one Git-generated trailer and
* consists of at least 25% trailers.
*/
- for (l = last_line(buf, len);
- l >= end_of_title;
- l = last_line(buf, l)) {
+ l = len;
+ while (last_line(&l, buf, l) && l >= end_of_title) {
const char *bol = buf + l;
const char *const *p;
- int separator_pos;
+ size_t separator_pos = 0;
if (bol[0] == COMMENT_LINE_CHAR) {
non_trailer_lines += possible_continuation_lines;
}
}
- separator_pos = find_separator(bol, TRAILER_SEPARATORS);
+ find_separator(&separator_pos, bol, TRAILER_SEPARATORS);
if (separator_pos >= 1 && !isspace(bol[0])) {
trailer_lines++;
possible_continuation_lines = 0;
}
/* Return the position of the end of the trailers. */
-static int find_trailer_end(const char *buf, size_t len)
+static size_t find_trailer_end(const char *buf, size_t len)
{
return len - ignore_non_trailer(buf, len);
}
size_t trailer_len = trailer_end - trailer_start;
char *buffer = git__malloc(trailer_len + 1);
+ if (buffer == NULL)
+ return NULL;
+
memcpy(buffer, message + trailer_start, trailer_len);
buffer[trailer_len] = 0;
size_t trailer_len;
char *trailer = extract_trailer_block(message, &trailer_len);
+ if (trailer == NULL)
+ return -1;
for (ptr = trailer;;) {
switch (state) {
assert(out && repo);
- git_pool_init(&pool, 1);
+ if ((error = git_pool_init(&pool, 1)) < 0)
+ goto on_error;
tx = git_pool_mallocz(&pool, sizeof(git_transaction));
if (!tx) {
goto on_error;
}
- if ((error = git_strmap_alloc(&tx->locks)) < 0) {
+ if ((error = git_strmap_new(&tx->locks)) < 0) {
error = -1;
goto on_error;
}
if ((error = git_refdb_lock(&node->payload, tx->db, refname)) < 0)
return error;
- git_strmap_insert(tx->locks, node->name, node, &error);
- if (error < 0)
+ if ((error = git_strmap_set(tx->locks, node->name, node)) < 0)
goto cleanup;
return 0;
static int find_locked(transaction_node **out, git_transaction *tx, const char *refname)
{
transaction_node *node;
- size_t pos;
- pos = git_strmap_lookup_index(tx->locks, refname);
- if (!git_strmap_valid_index(tx->locks, pos)) {
+ if ((node = git_strmap_get(tx->locks, refname)) == NULL) {
git_error_set(GIT_ERROR_REFERENCE, "the specified reference is not locked");
return GIT_ENOTFOUND;
}
- node = git_strmap_value_at(tx->locks, pos);
-
*out = node;
return 0;
}
return error;
}
- if (node->ref_type != GIT_REFERENCE_INVALID) {
+ if (node->ref_type == GIT_REFERENCE_INVALID) {
+ /* ref was locked but not modified */
+ if ((error = git_refdb_unlock(tx->db, node->payload, false, false, NULL, NULL, NULL)) < 0) {
+ return error;
+ }
+ node->committed = true;
+ } else {
if ((error = update_target(tx->db, node)) < 0)
return error;
}
#include "git2.h"
#include "buffer.h"
+#include "git2/sys/credential.h"
static int basic_next_token(
git_buf *out,
git_http_auth_context *ctx,
- const char *header_name,
- git_cred *c)
+ git_credential *c)
{
- git_cred_userpass_plaintext *cred;
+ git_credential_userpass_plaintext *cred;
git_buf raw = GIT_BUF_INIT;
int error = -1;
GIT_UNUSED(ctx);
- if (c->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) {
+ if (c->credtype != GIT_CREDENTIAL_USERPASS_PLAINTEXT) {
git_error_set(GIT_ERROR_INVALID, "invalid credential type for basic auth");
goto on_error;
}
- cred = (git_cred_userpass_plaintext *)c;
+ cred = (git_credential_userpass_plaintext *)c;
git_buf_printf(&raw, "%s:%s", cred->username, cred->password);
if (git_buf_oom(&raw) ||
- git_buf_printf(out, "%s: Basic ", header_name) < 0 ||
- git_buf_encode_base64(out, git_buf_cstr(&raw), raw.size) < 0 ||
- git_buf_puts(out, "\r\n") < 0)
+ git_buf_puts(out, "Basic ") < 0 ||
+ git_buf_encode_base64(out, git_buf_cstr(&raw), raw.size) < 0)
goto on_error;
error = 0;
}
static git_http_auth_context basic_context = {
- GIT_AUTHTYPE_BASIC,
- GIT_CREDTYPE_USERPASS_PLAINTEXT,
+ GIT_HTTP_AUTH_BASIC,
+ GIT_CREDENTIAL_USERPASS_PLAINTEXT,
+ 0,
NULL,
basic_next_token,
+ NULL,
NULL
};
int git_http_auth_basic(
- git_http_auth_context **out, const gitno_connection_data *connection_data)
+ git_http_auth_context **out, const git_net_url *url)
{
- GIT_UNUSED(connection_data);
+ GIT_UNUSED(url);
*out = &basic_context;
return 0;
}
int git_http_auth_dummy(
- git_http_auth_context **out, const gitno_connection_data *connection_data)
+ git_http_auth_context **out, const git_net_url *url)
{
- GIT_UNUSED(connection_data);
+ GIT_UNUSED(url);
*out = NULL;
- return 0;
+ return GIT_PASSTHROUGH;
}
#include "netops.h"
typedef enum {
- GIT_AUTHTYPE_BASIC = 1,
- GIT_AUTHTYPE_NEGOTIATE = 2,
-} git_http_authtype_t;
+ GIT_HTTP_AUTH_BASIC = 1,
+ GIT_HTTP_AUTH_NEGOTIATE = 2,
+ GIT_HTTP_AUTH_NTLM = 4,
+} git_http_auth_t;
typedef struct git_http_auth_context git_http_auth_context;
struct git_http_auth_context {
/** Type of scheme */
- git_http_authtype_t type;
+ git_http_auth_t type;
/** Supported credentials */
- git_credtype_t credtypes;
+ git_credential_t credtypes;
+
+ /** Connection affinity or request affinity */
+ unsigned connection_affinity : 1;
/** Sets the challenge on the authentication context */
int (*set_challenge)(git_http_auth_context *ctx, const char *challenge);
/** Gets the next authentication token from the context */
- int (*next_token)(git_buf *out, git_http_auth_context *ctx, const char *header_name, git_cred *cred);
+ int (*next_token)(git_buf *out, git_http_auth_context *ctx, git_credential *cred);
+
+ /** Examines if all tokens have been presented. */
+ int (*is_complete)(git_http_auth_context *ctx);
/** Frees the authentication context */
void (*free)(git_http_auth_context *ctx);
typedef struct {
/** Type of scheme */
- git_http_authtype_t type;
+ git_http_auth_t type;
/** Name of the scheme (as used in the Authorization header) */
const char *name;
/** Credential types this scheme supports */
- git_credtype_t credtypes;
+ git_credential_t credtypes;
/** Function to initialize an authentication context */
int (*init_context)(
git_http_auth_context **out,
- const gitno_connection_data *connection_data);
+ const git_net_url *url);
} git_http_auth_scheme;
int git_http_auth_dummy(
git_http_auth_context **out,
- const gitno_connection_data *connection_data);
+ const git_net_url *url);
int git_http_auth_basic(
git_http_auth_context **out,
- const gitno_connection_data *connection_data);
+ const git_net_url *url);
#endif
#include "auth_negotiate.h"
-#ifdef GIT_GSSAPI
+#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK)
#include "git2.h"
#include "buffer.h"
#include "auth.h"
+#include "git2/sys/credential.h"
+#ifdef GIT_GSSFRAMEWORK
+#import <GSS/GSS.h>
+#elif defined(GIT_GSSAPI)
#include <gssapi.h>
#include <krb5.h>
+#endif
static gss_OID_desc negotiate_oid_spnego =
{ 6, (void *) "\x2b\x06\x01\x05\x05\x02" };
return 0;
}
+static void negotiate_context_dispose(http_auth_negotiate_context *ctx)
+{
+ OM_uint32 status_minor;
+
+ if (ctx->gss_context != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context(
+ &status_minor, &ctx->gss_context, GSS_C_NO_BUFFER);
+ ctx->gss_context = GSS_C_NO_CONTEXT;
+ }
+
+ git_buf_dispose(&ctx->target);
+
+ git__free(ctx->challenge);
+ ctx->challenge = NULL;
+}
+
static int negotiate_next_token(
git_buf *buf,
git_http_auth_context *c,
- const char *header_name,
- git_cred *cred)
+ git_credential *cred)
{
http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
OM_uint32 status_major, status_minor;
size_t challenge_len;
int error = 0;
- assert(buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDTYPE_DEFAULT);
+ assert(buf && ctx && ctx->configured && cred && cred->credtype == GIT_CREDENTIAL_DEFAULT);
if (ctx->complete)
return 0;
if (GSS_ERROR(status_major)) {
negotiate_err_set(status_major, status_minor,
- "Could not parse principal");
+ "could not parse principal");
error = -1;
goto done;
}
challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0;
- if (challenge_len < 9) {
- git_error_set(GIT_ERROR_NET, "no negotiate challenge sent from server");
+ if (challenge_len < 9 || memcmp(ctx->challenge, "Negotiate", 9) != 0) {
+ git_error_set(GIT_ERROR_NET, "server did not request negotiate");
error = -1;
goto done;
- } else if (challenge_len > 9) {
+ }
+
+ if (challenge_len > 9) {
if (git_buf_decode_base64(&input_buf,
ctx->challenge + 10, challenge_len - 10) < 0) {
git_error_set(GIT_ERROR_NET, "invalid negotiate challenge from server");
input_token.length = input_buf.size;
input_token_ptr = &input_token;
} else if (ctx->gss_context != GSS_C_NO_CONTEXT) {
- git_error_set(GIT_ERROR_NET, "could not restart authentication");
- error = -1;
- goto done;
+ negotiate_context_dispose(ctx);
}
mech = &negotiate_oid_spnego;
- if (GSS_ERROR(status_major = gss_init_sec_context(
+ status_major = gss_init_sec_context(
&status_minor,
GSS_C_NO_CREDENTIAL,
&ctx->gss_context,
NULL,
&output_token,
NULL,
- NULL))) {
- negotiate_err_set(status_major, status_minor, "Negotiate failure");
+ NULL);
+
+ if (GSS_ERROR(status_major)) {
+ negotiate_err_set(status_major, status_minor, "negotiate failure");
error = -1;
goto done;
}
/* This message merely told us auth was complete; we do not respond. */
if (status_major == GSS_S_COMPLETE) {
+ negotiate_context_dispose(ctx);
ctx->complete = 1;
goto done;
}
- git_buf_printf(buf, "%s: Negotiate ", header_name);
+ if (output_token.length == 0) {
+ git_error_set(GIT_ERROR_NET, "GSSAPI did not return token");
+ error = -1;
+ goto done;
+ }
+
+ git_buf_puts(buf, "Negotiate ");
git_buf_encode_base64(buf, output_token.value, output_token.length);
- git_buf_puts(buf, "\r\n");
if (git_buf_oom(buf))
error = -1;
return error;
}
-static void negotiate_context_free(git_http_auth_context *c)
+static int negotiate_is_complete(git_http_auth_context *c)
{
http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
- OM_uint32 status_minor;
- if (ctx->gss_context != GSS_C_NO_CONTEXT) {
- gss_delete_sec_context(
- &status_minor, &ctx->gss_context, GSS_C_NO_BUFFER);
- ctx->gss_context = GSS_C_NO_CONTEXT;
- }
+ assert(ctx);
- git_buf_dispose(&ctx->target);
+ return (ctx->complete == 1);
+}
- git__free(ctx->challenge);
+static void negotiate_context_free(git_http_auth_context *c)
+{
+ http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
+
+ negotiate_context_dispose(ctx);
ctx->configured = 0;
ctx->complete = 0;
static int negotiate_init_context(
http_auth_negotiate_context *ctx,
- const gitno_connection_data *connection_data)
+ const git_net_url *url)
{
OM_uint32 status_major, status_minor;
gss_OID item, *oid;
size_t i;
/* Query supported mechanisms looking for SPNEGO) */
- if (GSS_ERROR(status_major =
- gss_indicate_mechs(&status_minor, &mechanism_list))) {
+ status_major = gss_indicate_mechs(&status_minor, &mechanism_list);
+
+ if (GSS_ERROR(status_major)) {
negotiate_err_set(status_major, status_minor,
"could not query mechanisms");
return -1;
}
git_buf_puts(&ctx->target, "HTTP@");
- git_buf_puts(&ctx->target, connection_data->host);
+ git_buf_puts(&ctx->target, url->host);
if (git_buf_oom(&ctx->target))
return -1;
int git_http_auth_negotiate(
git_http_auth_context **out,
- const gitno_connection_data *connection_data)
+ const git_net_url *url)
{
http_auth_negotiate_context *ctx;
ctx = git__calloc(1, sizeof(http_auth_negotiate_context));
GIT_ERROR_CHECK_ALLOC(ctx);
- if (negotiate_init_context(ctx, connection_data) < 0) {
+ if (negotiate_init_context(ctx, url) < 0) {
git__free(ctx);
return -1;
}
- ctx->parent.type = GIT_AUTHTYPE_NEGOTIATE;
- ctx->parent.credtypes = GIT_CREDTYPE_DEFAULT;
+ ctx->parent.type = GIT_HTTP_AUTH_NEGOTIATE;
+ ctx->parent.credtypes = GIT_CREDENTIAL_DEFAULT;
+ ctx->parent.connection_affinity = 1;
ctx->parent.set_challenge = negotiate_set_challenge;
ctx->parent.next_token = negotiate_next_token;
+ ctx->parent.is_complete = negotiate_is_complete;
ctx->parent.free = negotiate_context_free;
*out = (git_http_auth_context *)ctx;
#include "git2.h"
#include "auth.h"
-#ifdef GIT_GSSAPI
+#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK)
extern int git_http_auth_negotiate(
git_http_auth_context **out,
- const gitno_connection_data *connection_data);
+ const git_net_url *url);
#else
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "git2.h"
+#include "common.h"
+#include "buffer.h"
+#include "auth.h"
+#include "auth_ntlm.h"
+#include "git2/sys/credential.h"
+
+#ifdef GIT_NTLM
+
+#include "ntlm.h"
+
+typedef struct {
+ git_http_auth_context parent;
+ ntlm_client *ntlm;
+ char *challenge;
+ bool complete;
+} http_auth_ntlm_context;
+
+static int ntlm_set_challenge(
+ git_http_auth_context *c,
+ const char *challenge)
+{
+ http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
+
+ assert(ctx && challenge);
+
+ git__free(ctx->challenge);
+
+ ctx->challenge = git__strdup(challenge);
+ GIT_ERROR_CHECK_ALLOC(ctx->challenge);
+
+ return 0;
+}
+
+static int ntlm_set_credentials(http_auth_ntlm_context *ctx, git_credential *_cred)
+{
+ git_credential_userpass_plaintext *cred;
+ const char *sep, *username;
+ char *domain = NULL, *domainuser = NULL;
+ int error = 0;
+
+ assert(_cred->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT);
+ cred = (git_credential_userpass_plaintext *)_cred;
+
+ if ((sep = strchr(cred->username, '\\')) != NULL) {
+ domain = git__strndup(cred->username, (sep - cred->username));
+ GIT_ERROR_CHECK_ALLOC(domain);
+
+ domainuser = git__strdup(sep + 1);
+ GIT_ERROR_CHECK_ALLOC(domainuser);
+
+ username = domainuser;
+ } else {
+ username = cred->username;
+ }
+
+ if (ntlm_client_set_credentials(ctx->ntlm,
+ username, domain, cred->password) < 0) {
+ git_error_set(GIT_ERROR_NET, "could not set credentials: %s",
+ ntlm_client_errmsg(ctx->ntlm));
+ error = -1;
+ goto done;
+ }
+
+done:
+ git__free(domain);
+ git__free(domainuser);
+ return error;
+}
+
+static int ntlm_next_token(
+ git_buf *buf,
+ git_http_auth_context *c,
+ git_credential *cred)
+{
+ http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
+ git_buf input_buf = GIT_BUF_INIT;
+ const unsigned char *msg;
+ size_t challenge_len, msg_len;
+ int error = -1;
+
+ assert(buf && ctx && ctx->ntlm);
+
+ challenge_len = ctx->challenge ? strlen(ctx->challenge) : 0;
+
+ if (ctx->complete)
+ ntlm_client_reset(ctx->ntlm);
+
+ /*
+ * Set us complete now since it's the default case; the one
+ * incomplete case (successfully created a client request)
+ * will explicitly set that it requires a second step.
+ */
+ ctx->complete = true;
+
+ if (cred && ntlm_set_credentials(ctx, cred) != 0)
+ goto done;
+
+ if (challenge_len < 4) {
+ git_error_set(GIT_ERROR_NET, "no ntlm challenge sent from server");
+ goto done;
+ } else if (challenge_len == 4) {
+ if (memcmp(ctx->challenge, "NTLM", 4) != 0) {
+ git_error_set(GIT_ERROR_NET, "server did not request NTLM");
+ goto done;
+ }
+
+ if (ntlm_client_negotiate(&msg, &msg_len, ctx->ntlm) != 0) {
+ git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s",
+ ntlm_client_errmsg(ctx->ntlm));
+ goto done;
+ }
+
+ ctx->complete = false;
+ } else {
+ if (memcmp(ctx->challenge, "NTLM ", 5) != 0) {
+ git_error_set(GIT_ERROR_NET, "challenge from server was not NTLM");
+ goto done;
+ }
+
+ if (git_buf_decode_base64(&input_buf,
+ ctx->challenge + 5, challenge_len - 5) < 0) {
+ git_error_set(GIT_ERROR_NET, "invalid NTLM challenge from server");
+ goto done;
+ }
+
+ if (ntlm_client_set_challenge(ctx->ntlm,
+ (const unsigned char *)input_buf.ptr, input_buf.size) != 0) {
+ git_error_set(GIT_ERROR_NET, "ntlm challenge failed: %s",
+ ntlm_client_errmsg(ctx->ntlm));
+ goto done;
+ }
+
+ if (ntlm_client_response(&msg, &msg_len, ctx->ntlm) != 0) {
+ git_error_set(GIT_ERROR_NET, "ntlm authentication failed: %s",
+ ntlm_client_errmsg(ctx->ntlm));
+ goto done;
+ }
+ }
+
+ git_buf_puts(buf, "NTLM ");
+ git_buf_encode_base64(buf, (const char *)msg, msg_len);
+
+ if (git_buf_oom(buf))
+ goto done;
+
+ error = 0;
+
+done:
+ git_buf_dispose(&input_buf);
+ return error;
+}
+
+static int ntlm_is_complete(git_http_auth_context *c)
+{
+ http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
+
+ assert(ctx);
+ return (ctx->complete == true);
+}
+
+static void ntlm_context_free(git_http_auth_context *c)
+{
+ http_auth_ntlm_context *ctx = (http_auth_ntlm_context *)c;
+
+ ntlm_client_free(ctx->ntlm);
+ git__free(ctx->challenge);
+ git__free(ctx);
+}
+
+static int ntlm_init_context(
+ http_auth_ntlm_context *ctx,
+ const git_net_url *url)
+{
+ GIT_UNUSED(url);
+
+ if ((ctx->ntlm = ntlm_client_init(NTLM_CLIENT_DEFAULTS)) == NULL) {
+ git_error_set_oom();
+ return -1;
+ }
+
+ return 0;
+}
+
+int git_http_auth_ntlm(
+ git_http_auth_context **out,
+ const git_net_url *url)
+{
+ http_auth_ntlm_context *ctx;
+
+ GIT_UNUSED(url);
+
+ *out = NULL;
+
+ ctx = git__calloc(1, sizeof(http_auth_ntlm_context));
+ GIT_ERROR_CHECK_ALLOC(ctx);
+
+ if (ntlm_init_context(ctx, url) < 0) {
+ git__free(ctx);
+ return -1;
+ }
+
+ ctx->parent.type = GIT_HTTP_AUTH_NTLM;
+ ctx->parent.credtypes = GIT_CREDENTIAL_USERPASS_PLAINTEXT;
+ ctx->parent.connection_affinity = 1;
+ ctx->parent.set_challenge = ntlm_set_challenge;
+ ctx->parent.next_token = ntlm_next_token;
+ ctx->parent.is_complete = ntlm_is_complete;
+ ctx->parent.free = ntlm_context_free;
+
+ *out = (git_http_auth_context *)ctx;
+
+ return 0;
+}
+
+#endif /* GIT_NTLM */
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_transports_auth_ntlm_h__
+#define INCLUDE_transports_auth_ntlm_h__
+
+#include "git2.h"
+#include "auth.h"
+
+/* NTLM requires a full request/challenge/response */
+#define GIT_AUTH_STEPS_NTLM 2
+
+#ifdef GIT_NTLM
+
+#if defined(GIT_OPENSSL)
+# define CRYPT_OPENSSL
+#elif defined(GIT_MBEDTLS)
+# define CRYPT_MBEDTLS
+#elif defined(GIT_SECURE_TRANSPORT)
+# define CRYPT_COMMONCRYPTO
+#endif
+
+extern int git_http_auth_ntlm(
+ git_http_auth_context **out,
+ const git_net_url *url);
+
+#else
+
+#define git_http_auth_ntlm git_http_auth_dummy
+
+#endif /* GIT_NTLM */
+
+#endif
+
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "cred.h"
-
-#include "git2.h"
-#include "smart.h"
-#include "git2/cred_helpers.h"
-
-static int git_cred_ssh_key_type_new(
- git_cred **cred,
- const char *username,
- const char *publickey,
- const char *privatekey,
- const char *passphrase,
- git_credtype_t credtype);
-
-int git_cred_has_username(git_cred *cred)
-{
- if (cred->credtype == GIT_CREDTYPE_DEFAULT)
- return 0;
-
- return 1;
-}
-
-const char *git_cred__username(git_cred *cred)
-{
- switch (cred->credtype) {
- case GIT_CREDTYPE_USERNAME:
- {
- git_cred_username *c = (git_cred_username *) cred;
- return c->username;
- }
- case GIT_CREDTYPE_USERPASS_PLAINTEXT:
- {
- git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *) cred;
- return c->username;
- }
- case GIT_CREDTYPE_SSH_KEY:
- case GIT_CREDTYPE_SSH_MEMORY:
- {
- git_cred_ssh_key *c = (git_cred_ssh_key *) cred;
- return c->username;
- }
- case GIT_CREDTYPE_SSH_CUSTOM:
- {
- git_cred_ssh_custom *c = (git_cred_ssh_custom *) cred;
- return c->username;
- }
- case GIT_CREDTYPE_SSH_INTERACTIVE:
- {
- git_cred_ssh_interactive *c = (git_cred_ssh_interactive *) cred;
- return c->username;
- }
-
- default:
- return NULL;
- }
-}
-
-static void plaintext_free(struct git_cred *cred)
-{
- git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
-
- git__free(c->username);
-
- /* Zero the memory which previously held the password */
- if (c->password) {
- size_t pass_len = strlen(c->password);
- git__memzero(c->password, pass_len);
- git__free(c->password);
- }
-
- git__free(c);
-}
-
-int git_cred_userpass_plaintext_new(
- git_cred **cred,
- const char *username,
- const char *password)
-{
- git_cred_userpass_plaintext *c;
-
- assert(cred && username && password);
-
- c = git__malloc(sizeof(git_cred_userpass_plaintext));
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->parent.credtype = GIT_CREDTYPE_USERPASS_PLAINTEXT;
- c->parent.free = plaintext_free;
- c->username = git__strdup(username);
-
- if (!c->username) {
- git__free(c);
- return -1;
- }
-
- c->password = git__strdup(password);
-
- if (!c->password) {
- git__free(c->username);
- git__free(c);
- return -1;
- }
-
- *cred = &c->parent;
- return 0;
-}
-
-static void ssh_key_free(struct git_cred *cred)
-{
- git_cred_ssh_key *c =
- (git_cred_ssh_key *)cred;
-
- git__free(c->username);
-
- if (c->privatekey) {
- /* Zero the memory which previously held the private key */
- size_t key_len = strlen(c->privatekey);
- git__memzero(c->privatekey, key_len);
- git__free(c->privatekey);
- }
-
- if (c->passphrase) {
- /* Zero the memory which previously held the passphrase */
- size_t pass_len = strlen(c->passphrase);
- git__memzero(c->passphrase, pass_len);
- git__free(c->passphrase);
- }
-
- if (c->publickey) {
- /* Zero the memory which previously held the public key */
- size_t key_len = strlen(c->publickey);
- git__memzero(c->publickey, key_len);
- git__free(c->publickey);
- }
-
- git__free(c);
-}
-
-static void ssh_interactive_free(struct git_cred *cred)
-{
- git_cred_ssh_interactive *c = (git_cred_ssh_interactive *)cred;
-
- git__free(c->username);
-
- git__free(c);
-}
-
-static void ssh_custom_free(struct git_cred *cred)
-{
- git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred;
-
- git__free(c->username);
-
- if (c->publickey) {
- /* Zero the memory which previously held the publickey */
- size_t key_len = strlen(c->publickey);
- git__memzero(c->publickey, key_len);
- git__free(c->publickey);
- }
-
- git__free(c);
-}
-
-static void default_free(struct git_cred *cred)
-{
- git_cred_default *c = (git_cred_default *)cred;
-
- git__free(c);
-}
-
-static void username_free(struct git_cred *cred)
-{
- git__free(cred);
-}
-
-int git_cred_ssh_key_new(
- git_cred **cred,
- const char *username,
- const char *publickey,
- const char *privatekey,
- const char *passphrase)
-{
- return git_cred_ssh_key_type_new(
- cred,
- username,
- publickey,
- privatekey,
- passphrase,
- GIT_CREDTYPE_SSH_KEY);
-}
-
-int git_cred_ssh_key_memory_new(
- git_cred **cred,
- const char *username,
- const char *publickey,
- const char *privatekey,
- const char *passphrase)
-{
-#ifdef GIT_SSH_MEMORY_CREDENTIALS
- return git_cred_ssh_key_type_new(
- cred,
- username,
- publickey,
- privatekey,
- passphrase,
- GIT_CREDTYPE_SSH_MEMORY);
-#else
- GIT_UNUSED(cred);
- GIT_UNUSED(username);
- GIT_UNUSED(publickey);
- GIT_UNUSED(privatekey);
- GIT_UNUSED(passphrase);
-
- git_error_set(GIT_ERROR_INVALID,
- "this version of libgit2 was not built with ssh memory credentials.");
- return -1;
-#endif
-}
-
-static int git_cred_ssh_key_type_new(
- git_cred **cred,
- const char *username,
- const char *publickey,
- const char *privatekey,
- const char *passphrase,
- git_credtype_t credtype)
-{
- git_cred_ssh_key *c;
-
- assert(username && cred && privatekey);
-
- c = git__calloc(1, sizeof(git_cred_ssh_key));
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->parent.credtype = credtype;
- c->parent.free = ssh_key_free;
-
- c->username = git__strdup(username);
- GIT_ERROR_CHECK_ALLOC(c->username);
-
- c->privatekey = git__strdup(privatekey);
- GIT_ERROR_CHECK_ALLOC(c->privatekey);
-
- if (publickey) {
- c->publickey = git__strdup(publickey);
- GIT_ERROR_CHECK_ALLOC(c->publickey);
- }
-
- if (passphrase) {
- c->passphrase = git__strdup(passphrase);
- GIT_ERROR_CHECK_ALLOC(c->passphrase);
- }
-
- *cred = &c->parent;
- return 0;
-}
-
-int git_cred_ssh_interactive_new(
- git_cred **out,
- const char *username,
- git_cred_ssh_interactive_callback prompt_callback,
- void *payload)
-{
- git_cred_ssh_interactive *c;
-
- assert(out && username && prompt_callback);
-
- c = git__calloc(1, sizeof(git_cred_ssh_interactive));
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->parent.credtype = GIT_CREDTYPE_SSH_INTERACTIVE;
- c->parent.free = ssh_interactive_free;
-
- c->username = git__strdup(username);
- GIT_ERROR_CHECK_ALLOC(c->username);
-
- c->prompt_callback = prompt_callback;
- c->payload = payload;
-
- *out = &c->parent;
- return 0;
-}
-
-int git_cred_ssh_key_from_agent(git_cred **cred, const char *username) {
- git_cred_ssh_key *c;
-
- assert(username && cred);
-
- c = git__calloc(1, sizeof(git_cred_ssh_key));
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->parent.credtype = GIT_CREDTYPE_SSH_KEY;
- c->parent.free = ssh_key_free;
-
- c->username = git__strdup(username);
- GIT_ERROR_CHECK_ALLOC(c->username);
-
- c->privatekey = NULL;
-
- *cred = &c->parent;
- return 0;
-}
-
-int git_cred_ssh_custom_new(
- git_cred **cred,
- const char *username,
- const char *publickey,
- size_t publickey_len,
- git_cred_sign_callback sign_callback,
- void *payload)
-{
- git_cred_ssh_custom *c;
-
- assert(username && cred);
-
- c = git__calloc(1, sizeof(git_cred_ssh_custom));
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->parent.credtype = GIT_CREDTYPE_SSH_CUSTOM;
- c->parent.free = ssh_custom_free;
-
- c->username = git__strdup(username);
- GIT_ERROR_CHECK_ALLOC(c->username);
-
- if (publickey_len > 0) {
- c->publickey = git__malloc(publickey_len);
- GIT_ERROR_CHECK_ALLOC(c->publickey);
-
- memcpy(c->publickey, publickey, publickey_len);
- }
-
- c->publickey_len = publickey_len;
- c->sign_callback = sign_callback;
- c->payload = payload;
-
- *cred = &c->parent;
- return 0;
-}
-
-int git_cred_default_new(git_cred **cred)
-{
- git_cred_default *c;
-
- assert(cred);
-
- c = git__calloc(1, sizeof(git_cred_default));
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->credtype = GIT_CREDTYPE_DEFAULT;
- c->free = default_free;
-
- *cred = c;
- return 0;
-}
-
-int git_cred_username_new(git_cred **cred, const char *username)
-{
- git_cred_username *c;
- size_t len, allocsize;
-
- assert(cred);
-
- len = strlen(username);
-
- GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, sizeof(git_cred_username), len);
- GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, allocsize, 1);
- c = git__malloc(allocsize);
- GIT_ERROR_CHECK_ALLOC(c);
-
- c->parent.credtype = GIT_CREDTYPE_USERNAME;
- c->parent.free = username_free;
- memcpy(c->username, username, len + 1);
-
- *cred = (git_cred *) c;
- return 0;
-}
-
-void git_cred_free(git_cred *cred)
-{
- if (!cred)
- return;
-
- cred->free(cred);
-}
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_transports_cred_h__
-#define INCLUDE_transports_cred_h__
-
-#include "common.h"
-
-#include "git2/transport.h"
-
-const char *git_cred__username(git_cred *cred);
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "common.h"
-
-#include "git2/cred_helpers.h"
-
-int git_cred_userpass(
- git_cred **cred,
- const char *url,
- const char *user_from_url,
- unsigned int allowed_types,
- void *payload)
-{
- git_cred_userpass_payload *userpass = (git_cred_userpass_payload*)payload;
- const char *effective_username = NULL;
-
- GIT_UNUSED(url);
-
- if (!userpass || !userpass->password) return -1;
-
- /* Username resolution: a username can be passed with the URL, the
- * credentials payload, or both. Here's what we do. Note that if we get
- * this far, we know that any password the url may contain has already
- * failed at least once, so we ignore it.
- *
- * | Payload | URL | Used |
- * +-------------+----------+-----------+
- * | yes | no | payload |
- * | yes | yes | payload |
- * | no | yes | url |
- * | no | no | FAIL |
- */
- if (userpass->username)
- effective_username = userpass->username;
- else if (user_from_url)
- effective_username = user_from_url;
- else
- return -1;
-
- if (GIT_CREDTYPE_USERNAME & allowed_types)
- return git_cred_username_new(cred, effective_username);
-
- if ((GIT_CREDTYPE_USERPASS_PLAINTEXT & allowed_types) == 0 ||
- git_cred_userpass_plaintext_new(cred, effective_username, userpass->password) < 0)
- return -1;
-
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+
+#include "git2/credential.h"
+#include "git2/sys/credential.h"
+#include "git2/credential_helpers.h"
+
+static int git_credential_ssh_key_type_new(
+ git_credential **cred,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase,
+ git_credential_t credtype);
+
+int git_credential_has_username(git_credential *cred)
+{
+ if (cred->credtype == GIT_CREDENTIAL_DEFAULT)
+ return 0;
+
+ return 1;
+}
+
+const char *git_credential_get_username(git_credential *cred)
+{
+ switch (cred->credtype) {
+ case GIT_CREDENTIAL_USERNAME:
+ {
+ git_credential_username *c = (git_credential_username *) cred;
+ return c->username;
+ }
+ case GIT_CREDENTIAL_USERPASS_PLAINTEXT:
+ {
+ git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *) cred;
+ return c->username;
+ }
+ case GIT_CREDENTIAL_SSH_KEY:
+ case GIT_CREDENTIAL_SSH_MEMORY:
+ {
+ git_credential_ssh_key *c = (git_credential_ssh_key *) cred;
+ return c->username;
+ }
+ case GIT_CREDENTIAL_SSH_CUSTOM:
+ {
+ git_credential_ssh_custom *c = (git_credential_ssh_custom *) cred;
+ return c->username;
+ }
+ case GIT_CREDENTIAL_SSH_INTERACTIVE:
+ {
+ git_credential_ssh_interactive *c = (git_credential_ssh_interactive *) cred;
+ return c->username;
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+static void plaintext_free(struct git_credential *cred)
+{
+ git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred;
+
+ git__free(c->username);
+
+ /* Zero the memory which previously held the password */
+ if (c->password) {
+ size_t pass_len = strlen(c->password);
+ git__memzero(c->password, pass_len);
+ git__free(c->password);
+ }
+
+ git__free(c);
+}
+
+int git_credential_userpass_plaintext_new(
+ git_credential **cred,
+ const char *username,
+ const char *password)
+{
+ git_credential_userpass_plaintext *c;
+
+ assert(cred && username && password);
+
+ c = git__malloc(sizeof(git_credential_userpass_plaintext));
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->parent.credtype = GIT_CREDENTIAL_USERPASS_PLAINTEXT;
+ c->parent.free = plaintext_free;
+ c->username = git__strdup(username);
+
+ if (!c->username) {
+ git__free(c);
+ return -1;
+ }
+
+ c->password = git__strdup(password);
+
+ if (!c->password) {
+ git__free(c->username);
+ git__free(c);
+ return -1;
+ }
+
+ *cred = &c->parent;
+ return 0;
+}
+
+static void ssh_key_free(struct git_credential *cred)
+{
+ git_credential_ssh_key *c =
+ (git_credential_ssh_key *)cred;
+
+ git__free(c->username);
+
+ if (c->privatekey) {
+ /* Zero the memory which previously held the private key */
+ size_t key_len = strlen(c->privatekey);
+ git__memzero(c->privatekey, key_len);
+ git__free(c->privatekey);
+ }
+
+ if (c->passphrase) {
+ /* Zero the memory which previously held the passphrase */
+ size_t pass_len = strlen(c->passphrase);
+ git__memzero(c->passphrase, pass_len);
+ git__free(c->passphrase);
+ }
+
+ if (c->publickey) {
+ /* Zero the memory which previously held the public key */
+ size_t key_len = strlen(c->publickey);
+ git__memzero(c->publickey, key_len);
+ git__free(c->publickey);
+ }
+
+ git__free(c);
+}
+
+static void ssh_interactive_free(struct git_credential *cred)
+{
+ git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred;
+
+ git__free(c->username);
+
+ git__free(c);
+}
+
+static void ssh_custom_free(struct git_credential *cred)
+{
+ git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred;
+
+ git__free(c->username);
+
+ if (c->publickey) {
+ /* Zero the memory which previously held the publickey */
+ size_t key_len = strlen(c->publickey);
+ git__memzero(c->publickey, key_len);
+ git__free(c->publickey);
+ }
+
+ git__free(c);
+}
+
+static void default_free(struct git_credential *cred)
+{
+ git_credential_default *c = (git_credential_default *)cred;
+
+ git__free(c);
+}
+
+static void username_free(struct git_credential *cred)
+{
+ git__free(cred);
+}
+
+int git_credential_ssh_key_new(
+ git_credential **cred,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase)
+{
+ return git_credential_ssh_key_type_new(
+ cred,
+ username,
+ publickey,
+ privatekey,
+ passphrase,
+ GIT_CREDENTIAL_SSH_KEY);
+}
+
+int git_credential_ssh_key_memory_new(
+ git_credential **cred,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase)
+{
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+ return git_credential_ssh_key_type_new(
+ cred,
+ username,
+ publickey,
+ privatekey,
+ passphrase,
+ GIT_CREDENTIAL_SSH_MEMORY);
+#else
+ GIT_UNUSED(cred);
+ GIT_UNUSED(username);
+ GIT_UNUSED(publickey);
+ GIT_UNUSED(privatekey);
+ GIT_UNUSED(passphrase);
+
+ git_error_set(GIT_ERROR_INVALID,
+ "this version of libgit2 was not built with ssh memory credentials.");
+ return -1;
+#endif
+}
+
+static int git_credential_ssh_key_type_new(
+ git_credential **cred,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase,
+ git_credential_t credtype)
+{
+ git_credential_ssh_key *c;
+
+ assert(username && cred && privatekey);
+
+ c = git__calloc(1, sizeof(git_credential_ssh_key));
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->parent.credtype = credtype;
+ c->parent.free = ssh_key_free;
+
+ c->username = git__strdup(username);
+ GIT_ERROR_CHECK_ALLOC(c->username);
+
+ c->privatekey = git__strdup(privatekey);
+ GIT_ERROR_CHECK_ALLOC(c->privatekey);
+
+ if (publickey) {
+ c->publickey = git__strdup(publickey);
+ GIT_ERROR_CHECK_ALLOC(c->publickey);
+ }
+
+ if (passphrase) {
+ c->passphrase = git__strdup(passphrase);
+ GIT_ERROR_CHECK_ALLOC(c->passphrase);
+ }
+
+ *cred = &c->parent;
+ return 0;
+}
+
+int git_credential_ssh_interactive_new(
+ git_credential **out,
+ const char *username,
+ git_credential_ssh_interactive_cb prompt_callback,
+ void *payload)
+{
+ git_credential_ssh_interactive *c;
+
+ assert(out && username && prompt_callback);
+
+ c = git__calloc(1, sizeof(git_credential_ssh_interactive));
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->parent.credtype = GIT_CREDENTIAL_SSH_INTERACTIVE;
+ c->parent.free = ssh_interactive_free;
+
+ c->username = git__strdup(username);
+ GIT_ERROR_CHECK_ALLOC(c->username);
+
+ c->prompt_callback = prompt_callback;
+ c->payload = payload;
+
+ *out = &c->parent;
+ return 0;
+}
+
+int git_credential_ssh_key_from_agent(git_credential **cred, const char *username) {
+ git_credential_ssh_key *c;
+
+ assert(username && cred);
+
+ c = git__calloc(1, sizeof(git_credential_ssh_key));
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->parent.credtype = GIT_CREDENTIAL_SSH_KEY;
+ c->parent.free = ssh_key_free;
+
+ c->username = git__strdup(username);
+ GIT_ERROR_CHECK_ALLOC(c->username);
+
+ c->privatekey = NULL;
+
+ *cred = &c->parent;
+ return 0;
+}
+
+int git_credential_ssh_custom_new(
+ git_credential **cred,
+ const char *username,
+ const char *publickey,
+ size_t publickey_len,
+ git_credential_sign_cb sign_callback,
+ void *payload)
+{
+ git_credential_ssh_custom *c;
+
+ assert(username && cred);
+
+ c = git__calloc(1, sizeof(git_credential_ssh_custom));
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->parent.credtype = GIT_CREDENTIAL_SSH_CUSTOM;
+ c->parent.free = ssh_custom_free;
+
+ c->username = git__strdup(username);
+ GIT_ERROR_CHECK_ALLOC(c->username);
+
+ if (publickey_len > 0) {
+ c->publickey = git__malloc(publickey_len);
+ GIT_ERROR_CHECK_ALLOC(c->publickey);
+
+ memcpy(c->publickey, publickey, publickey_len);
+ }
+
+ c->publickey_len = publickey_len;
+ c->sign_callback = sign_callback;
+ c->payload = payload;
+
+ *cred = &c->parent;
+ return 0;
+}
+
+int git_credential_default_new(git_credential **cred)
+{
+ git_credential_default *c;
+
+ assert(cred);
+
+ c = git__calloc(1, sizeof(git_credential_default));
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->credtype = GIT_CREDENTIAL_DEFAULT;
+ c->free = default_free;
+
+ *cred = c;
+ return 0;
+}
+
+int git_credential_username_new(git_credential **cred, const char *username)
+{
+ git_credential_username *c;
+ size_t len, allocsize;
+
+ assert(cred);
+
+ len = strlen(username);
+
+ GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, sizeof(git_credential_username), len);
+ GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, allocsize, 1);
+ c = git__malloc(allocsize);
+ GIT_ERROR_CHECK_ALLOC(c);
+
+ c->parent.credtype = GIT_CREDENTIAL_USERNAME;
+ c->parent.free = username_free;
+ memcpy(c->username, username, len + 1);
+
+ *cred = (git_credential *) c;
+ return 0;
+}
+
+void git_credential_free(git_credential *cred)
+{
+ if (!cred)
+ return;
+
+ cred->free(cred);
+}
+
+/* Deprecated credential functions */
+
+#ifndef GIT_DEPRECATE_HARD
+int git_cred_has_username(git_credential *cred)
+{
+ return git_credential_has_username(cred);
+}
+
+const char *git_cred_get_username(git_credential *cred)
+{
+ return git_credential_get_username(cred);
+}
+
+int git_cred_userpass_plaintext_new(
+ git_credential **out,
+ const char *username,
+ const char *password)
+{
+ return git_credential_userpass_plaintext_new(out,username, password);
+}
+
+int git_cred_default_new(git_credential **out)
+{
+ return git_credential_default_new(out);
+}
+
+int git_cred_username_new(git_credential **out, const char *username)
+{
+ return git_credential_username_new(out, username);
+}
+
+int git_cred_ssh_key_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase)
+{
+ return git_credential_ssh_key_new(out, username,
+ publickey, privatekey, passphrase);
+}
+
+int git_cred_ssh_key_memory_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ const char *privatekey,
+ const char *passphrase)
+{
+ return git_credential_ssh_key_memory_new(out, username,
+ publickey, privatekey, passphrase);
+}
+
+int git_cred_ssh_interactive_new(
+ git_credential **out,
+ const char *username,
+ git_credential_ssh_interactive_cb prompt_callback,
+ void *payload)
+{
+ return git_credential_ssh_interactive_new(out, username,
+ prompt_callback, payload);
+}
+
+int git_cred_ssh_key_from_agent(
+ git_credential **out,
+ const char *username)
+{
+ return git_credential_ssh_key_from_agent(out, username);
+}
+
+int git_cred_ssh_custom_new(
+ git_credential **out,
+ const char *username,
+ const char *publickey,
+ size_t publickey_len,
+ git_credential_sign_cb sign_callback,
+ void *payload)
+{
+ return git_credential_ssh_custom_new(out, username,
+ publickey, publickey_len, sign_callback, payload);
+}
+
+void git_cred_free(git_credential *cred)
+{
+ git_credential_free(cred);
+}
+#endif
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+
+#include "git2/credential_helpers.h"
+
+int git_credential_userpass(
+ git_credential **cred,
+ const char *url,
+ const char *user_from_url,
+ unsigned int allowed_types,
+ void *payload)
+{
+ git_credential_userpass_payload *userpass = (git_credential_userpass_payload*)payload;
+ const char *effective_username = NULL;
+
+ GIT_UNUSED(url);
+
+ if (!userpass || !userpass->password) return -1;
+
+ /* Username resolution: a username can be passed with the URL, the
+ * credentials payload, or both. Here's what we do. Note that if we get
+ * this far, we know that any password the url may contain has already
+ * failed at least once, so we ignore it.
+ *
+ * | Payload | URL | Used |
+ * +-------------+----------+-----------+
+ * | yes | no | payload |
+ * | yes | yes | payload |
+ * | no | yes | url |
+ * | no | no | FAIL |
+ */
+ if (userpass->username)
+ effective_username = userpass->username;
+ else if (user_from_url)
+ effective_username = user_from_url;
+ else
+ return -1;
+
+ if (GIT_CREDENTIAL_USERNAME & allowed_types)
+ return git_credential_username_new(cred, effective_username);
+
+ if ((GIT_CREDENTIAL_USERPASS_PLAINTEXT & allowed_types) == 0 ||
+ git_credential_userpass_plaintext_new(cred, effective_username, userpass->password) < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Deprecated credential functions */
+
+#ifndef GIT_DEPRECATE_HARD
+int git_cred_userpass(
+ git_credential **out,
+ const char *url,
+ const char *user_from_url,
+ unsigned int allowed_types,
+ void *payload)
+{
+ return git_credential_userpass(out, url, user_from_url,
+ allowed_types, payload);
+}
+#endif
const char *url,
git_smart_subtransport_stream **stream)
{
- char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
+ git_net_url urldata = GIT_NET_URL_INIT;
const char *stream_url = url;
+ const char *host, *port;
git_proto_stream *s;
int error;
if (!git__prefixcmp(url, prefix_git))
stream_url += strlen(prefix_git);
- if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, GIT_DEFAULT_PORT)) < 0)
+ if ((error = git_net_url_parse(&urldata, url)) < 0)
return error;
- error = git_proto_stream_alloc(t, stream_url, cmd_uploadpack, host, port, stream);
+ host = urldata.host;
+ port = urldata.port ? urldata.port : GIT_DEFAULT_PORT;
- git__free(host);
- git__free(port);
- git__free(path);
- git__free(user);
- git__free(pass);
+ error = git_proto_stream_alloc(t, stream_url, cmd_uploadpack, host, port, stream);
+ git_net_url_dispose(&urldata);
if (error < 0) {
git_proto_stream_free(*stream);
const char *url,
git_smart_subtransport_stream **stream)
{
- char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
+ git_net_url urldata = GIT_NET_URL_INIT;
const char *stream_url = url;
git_proto_stream *s;
int error;
if (!git__prefixcmp(url, prefix_git))
stream_url += strlen(prefix_git);
- if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, GIT_DEFAULT_PORT)) < 0)
+ if ((error = git_net_url_parse(&urldata, url)) < 0)
return error;
- error = git_proto_stream_alloc(t, stream_url, cmd_receivepack, host, port, stream);
+ error = git_proto_stream_alloc(t, stream_url, cmd_receivepack, urldata.host, urldata.port, stream);
- git__free(host);
- git__free(port);
- git__free(path);
- git__free(user);
- git__free(pass);
+ git_net_url_dispose(&urldata);
if (error < 0) {
git_proto_stream_free(*stream);
#include "git2.h"
#include "http_parser.h"
#include "buffer.h"
+#include "net.h"
#include "netops.h"
#include "global.h"
#include "remote.h"
+#include "git2/sys/credential.h"
#include "smart.h"
#include "auth.h"
#include "http.h"
#include "auth_negotiate.h"
+#include "auth_ntlm.h"
+#include "trace.h"
#include "streams/tls.h"
#include "streams/socket.h"
+#include "httpclient.h"
-git_http_auth_scheme auth_schemes[] = {
- { GIT_AUTHTYPE_NEGOTIATE, "Negotiate", GIT_CREDTYPE_DEFAULT, git_http_auth_negotiate },
- { GIT_AUTHTYPE_BASIC, "Basic", GIT_CREDTYPE_USERPASS_PLAINTEXT, git_http_auth_basic },
-};
-
-static const char *upload_pack_service = "upload-pack";
-static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
-static const char *upload_pack_service_url = "/git-upload-pack";
-static const char *receive_pack_service = "receive-pack";
-static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive-pack";
-static const char *receive_pack_service_url = "/git-receive-pack";
-static const char *get_verb = "GET";
-static const char *post_verb = "POST";
-
-#define AUTH_HEADER_SERVER "Authorization"
-#define AUTH_HEADER_PROXY "Proxy-Authorization"
-
-#define SERVER_TYPE_REMOTE "remote"
-#define SERVER_TYPE_PROXY "proxy"
-
-#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
+bool git_http__expect_continue = false;
-#define PARSE_ERROR_GENERIC -1
-#define PARSE_ERROR_REPLAY -2
-/** Look at the user field */
-#define PARSE_ERROR_EXT -3
+typedef enum {
+ HTTP_STATE_NONE = 0,
+ HTTP_STATE_SENDING_REQUEST,
+ HTTP_STATE_RECEIVING_RESPONSE,
+ HTTP_STATE_DONE
+} http_state;
-#define CHUNK_SIZE 4096
-
-enum last_cb {
- NONE,
- FIELD,
- VALUE
-};
+typedef struct {
+ git_http_method method;
+ const char *url;
+ const char *request_type;
+ const char *response_type;
+ unsigned chunked : 1;
+} http_service;
typedef struct {
git_smart_subtransport_stream parent;
- const char *service;
- const char *service_url;
- char *redirect_url;
- const char *verb;
- char *chunk_buffer;
- unsigned chunk_buffer_len;
- unsigned sent_request : 1,
- received_response : 1,
- chunked : 1;
+ const http_service *service;
+ http_state state;
+ unsigned replay_count;
} http_stream;
typedef struct {
- gitno_connection_data url;
- git_stream *stream;
-
- git_cred *cred;
- git_cred *url_cred;
+ git_net_url url;
- git_vector auth_challenges;
- git_vector auth_contexts;
+ git_credential *cred;
+ unsigned auth_schemetypes;
+ unsigned url_cred_presented : 1;
} http_server;
typedef struct {
git_smart_subtransport parent;
transport_smart *owner;
- git_stream *gitserver_stream;
- bool connected;
http_server server;
-
http_server proxy;
- char *proxy_url;
- git_proxy_options proxy_opts;
-
- /* Parser structures */
- http_parser parser;
- http_parser_settings settings;
- gitno_buffer parse_buffer;
- git_buf parse_header_name;
- git_buf parse_header_value;
- char parse_buffer_data[NETIO_BUFSIZE];
- char *content_type;
- char *content_length;
- char *location;
- enum last_cb last_cb;
- int parse_error;
- int error;
- unsigned parse_finished : 1,
- replay_count : 3;
+
+ git_http_client *http_client;
} http_subtransport;
-typedef struct {
- http_stream *s;
- http_subtransport *t;
+static const http_service upload_pack_ls_service = {
+ GIT_HTTP_METHOD_GET, "/info/refs?service=git-upload-pack",
+ NULL,
+ "application/x-git-upload-pack-advertisement",
+ 0
+};
+static const http_service upload_pack_service = {
+ GIT_HTTP_METHOD_POST, "/git-upload-pack",
+ "application/x-git-upload-pack-request",
+ "application/x-git-upload-pack-result",
+ 0
+};
+static const http_service receive_pack_ls_service = {
+ GIT_HTTP_METHOD_GET, "/info/refs?service=git-receive-pack",
+ NULL,
+ "application/x-git-receive-pack-advertisement",
+ 0
+};
+static const http_service receive_pack_service = {
+ GIT_HTTP_METHOD_POST, "/git-receive-pack",
+ "application/x-git-receive-pack-request",
+ "application/x-git-receive-pack-result",
+ 1
+};
+
+#define SERVER_TYPE_REMOTE "remote"
+#define SERVER_TYPE_PROXY "proxy"
- /* Target buffer details from read() */
- char *buffer;
- size_t buf_size;
- size_t *bytes_read;
-} parser_context;
+#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
-static bool credtype_match(git_http_auth_scheme *scheme, void *data)
+static int apply_url_credentials(
+ git_credential **cred,
+ unsigned int allowed_types,
+ const char *username,
+ const char *password)
{
- unsigned int credtype = *(unsigned int *)data;
+ if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT)
+ return git_credential_userpass_plaintext_new(cred, username, password);
+
+ if ((allowed_types & GIT_CREDENTIAL_DEFAULT) && *username == '\0' && *password == '\0')
+ return git_credential_default_new(cred);
- return !!(scheme->credtypes & credtype);
+ return GIT_PASSTHROUGH;
}
-static bool challenge_match(git_http_auth_scheme *scheme, void *data)
+GIT_INLINE(void) free_cred(git_credential **cred)
{
- const char *scheme_name = scheme->name;
- const char *challenge = (const char *)data;
- size_t scheme_len;
-
- scheme_len = strlen(scheme_name);
- return (strncasecmp(challenge, scheme_name, scheme_len) == 0 &&
- (challenge[scheme_len] == '\0' || challenge[scheme_len] == ' '));
+ if (*cred) {
+ git_credential_free(*cred);
+ (*cred) = NULL;
+ }
}
-static int auth_context_match(
- git_http_auth_context **out,
+static int handle_auth(
http_server *server,
- bool (*scheme_match)(git_http_auth_scheme *scheme, void *data),
- void *data)
+ const char *server_type,
+ const char *url,
+ unsigned int allowed_schemetypes,
+ unsigned int allowed_credtypes,
+ git_credential_acquire_cb callback,
+ void *callback_payload)
{
- git_http_auth_scheme *scheme = NULL;
- git_http_auth_context *context = NULL, *c;
- size_t i;
+ int error = 1;
- *out = NULL;
+ if (server->cred)
+ free_cred(&server->cred);
- for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
- if (scheme_match(&auth_schemes[i], data)) {
- scheme = &auth_schemes[i];
- break;
- }
+ /* Start with URL-specified credentials, if there were any. */
+ if ((allowed_credtypes & GIT_CREDENTIAL_USERPASS_PLAINTEXT) &&
+ !server->url_cred_presented &&
+ server->url.username &&
+ server->url.password) {
+ error = apply_url_credentials(&server->cred, allowed_credtypes, server->url.username, server->url.password);
+ server->url_cred_presented = 1;
+
+ /* treat GIT_PASSTHROUGH as if callback isn't set */
+ if (error == GIT_PASSTHROUGH)
+ error = 1;
}
- if (!scheme)
- return 0;
+ if (error > 0 && callback) {
+ error = callback(&server->cred, url, server->url.username, allowed_credtypes, callback_payload);
- /* See if authentication has already started for this scheme */
- git_vector_foreach(&server->auth_contexts, i, c) {
- if (c->type == scheme->type) {
- context = c;
- break;
- }
+ /* treat GIT_PASSTHROUGH as if callback isn't set */
+ if (error == GIT_PASSTHROUGH)
+ error = 1;
}
- if (!context) {
- if (scheme->init_context(&context, &server->url) < 0)
- return -1;
- else if (!context)
- return 0;
- else if (git_vector_insert(&server->auth_contexts, context) < 0)
- return -1;
+ if (error > 0) {
+ git_error_set(GIT_ERROR_HTTP, "%s authentication required but no callback set", server_type);
+ error = -1;
}
- *out = context;
+ if (!error)
+ server->auth_schemetypes = allowed_schemetypes;
- return 0;
+ return error;
}
-static int apply_credentials(
- git_buf *buf,
- http_server *server,
- const char *header_name)
+GIT_INLINE(int) handle_remote_auth(
+ http_stream *stream,
+ git_http_response *response)
{
- git_cred *cred = server->cred;
- git_http_auth_context *context;
-
- /* Apply the credentials given to us in the URL */
- if (!cred && server->url.user && server->url.pass) {
- if (!server->url_cred &&
- git_cred_userpass_plaintext_new(&server->url_cred,
- server->url.user, server->url.pass) < 0)
- return -1;
-
- cred = server->url_cred;
- }
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
- if (!cred)
- return 0;
-
- /* Get or create a context for the best scheme for this cred type */
- if (auth_context_match(&context, server,
- credtype_match, &cred->credtype) < 0)
+ if (response->server_auth_credtypes == 0) {
+ git_error_set(GIT_ERROR_HTTP, "server requires authentication that we do not support");
return -1;
-
- if (!context)
- return 0;
-
- return context->next_token(buf, context, header_name, cred);
-}
-
-static int gen_request(
- git_buf *buf,
- http_stream *s,
- size_t content_length)
-{
- http_subtransport *t = OWNING_SUBTRANSPORT(s);
- const char *path = t->server.url.path ? t->server.url.path : "/";
- size_t i;
-
- if (t->proxy_opts.type == GIT_PROXY_SPECIFIED)
- git_buf_printf(buf, "%s %s://%s:%s%s%s HTTP/1.1\r\n",
- s->verb,
- t->server.url.use_ssl ? "https" : "http",
- t->server.url.host,
- t->server.url.port,
- path, s->service_url);
- else
- git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n",
- s->verb, path, s->service_url);
-
- git_buf_puts(buf, "User-Agent: ");
- git_http__user_agent(buf);
- git_buf_puts(buf, "\r\n");
- git_buf_printf(buf, "Host: %s", t->server.url.host);
- if (strcmp(t->server.url.port, gitno__default_port(&t->server.url)) != 0) {
- git_buf_printf(buf, ":%s", t->server.url.port);
}
- git_buf_puts(buf, "\r\n");
-
- if (s->chunked || content_length > 0) {
- git_buf_printf(buf, "Accept: application/x-git-%s-result\r\n", s->service);
- git_buf_printf(buf, "Content-Type: application/x-git-%s-request\r\n", s->service);
-
- if (s->chunked)
- git_buf_puts(buf, "Transfer-Encoding: chunked\r\n");
- else
- git_buf_printf(buf, "Content-Length: %"PRIuZ "\r\n", content_length);
- } else
- git_buf_puts(buf, "Accept: */*\r\n");
-
- for (i = 0; i < t->owner->custom_headers.count; i++) {
- if (t->owner->custom_headers.strings[i])
- git_buf_printf(buf, "%s\r\n", t->owner->custom_headers.strings[i]);
- }
-
- /* Apply proxy and server credentials to the request */
- if (t->proxy_opts.type != GIT_PROXY_NONE &&
- apply_credentials(buf, &t->proxy, AUTH_HEADER_PROXY) < 0)
- return -1;
- if (apply_credentials(buf, &t->server, AUTH_HEADER_SERVER) < 0)
- return -1;
-
- git_buf_puts(buf, "\r\n");
-
- if (git_buf_oom(buf))
- return -1;
-
- return 0;
+ /* Otherwise, prompt for credentials. */
+ return handle_auth(
+ &transport->server,
+ SERVER_TYPE_REMOTE,
+ transport->owner->url,
+ response->server_auth_schemetypes,
+ response->server_auth_credtypes,
+ transport->owner->cred_acquire_cb,
+ transport->owner->cred_acquire_payload);
}
-static int parse_authenticate_response(
- http_server *server,
- int *allowed_types)
+GIT_INLINE(int) handle_proxy_auth(
+ http_stream *stream,
+ git_http_response *response)
{
- git_http_auth_context *context;
- char *challenge;
- size_t i;
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
- git_vector_foreach(&server->auth_challenges, i, challenge) {
- if (auth_context_match(&context, server,
- challenge_match, challenge) < 0)
- return -1;
- else if (!context)
- continue;
-
- if (context->set_challenge &&
- context->set_challenge(context, challenge) < 0)
- return -1;
-
- *allowed_types |= context->credtypes;
+ if (response->proxy_auth_credtypes == 0) {
+ git_error_set(GIT_ERROR_HTTP, "proxy requires authentication that we do not support");
+ return -1;
}
- return 0;
+ /* Otherwise, prompt for credentials. */
+ return handle_auth(
+ &transport->proxy,
+ SERVER_TYPE_PROXY,
+ transport->owner->proxy.url,
+ response->server_auth_schemetypes,
+ response->proxy_auth_credtypes,
+ transport->owner->proxy.credentials,
+ transport->owner->proxy.payload);
}
-static int on_header_ready(http_subtransport *t)
+
+static int handle_response(
+ bool *complete,
+ http_stream *stream,
+ git_http_response *response,
+ bool allow_replay)
{
- git_buf *name = &t->parse_header_name;
- git_buf *value = &t->parse_header_value;
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
+ int error;
- if (!strcasecmp("Content-Type", git_buf_cstr(name))) {
- if (t->content_type) {
- git_error_set(GIT_ERROR_NET, "multiple Content-Type headers");
- return -1;
- }
+ *complete = false;
- t->content_type = git__strdup(git_buf_cstr(value));
- GIT_ERROR_CHECK_ALLOC(t->content_type);
- }
- else if (!strcasecmp("Content-Length", git_buf_cstr(name))) {
- if (t->content_length) {
- git_error_set(GIT_ERROR_NET, "multiple Content-Length headers");
+ if (allow_replay && git_http_response_is_redirect(response)) {
+ if (!response->location) {
+ git_error_set(GIT_ERROR_HTTP, "redirect without location");
return -1;
}
- t->content_length = git__strdup(git_buf_cstr(value));
- GIT_ERROR_CHECK_ALLOC(t->content_length);
- }
- else if (!strcasecmp("Proxy-Authenticate", git_buf_cstr(name))) {
- char *dup = git__strdup(git_buf_cstr(value));
- GIT_ERROR_CHECK_ALLOC(dup);
-
- if (git_vector_insert(&t->proxy.auth_challenges, dup) < 0)
- return -1;
- }
- else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
- char *dup = git__strdup(git_buf_cstr(value));
- GIT_ERROR_CHECK_ALLOC(dup);
-
- if (git_vector_insert(&t->server.auth_challenges, dup) < 0)
- return -1;
- }
- else if (!strcasecmp("Location", git_buf_cstr(name))) {
- if (t->location) {
- git_error_set(GIT_ERROR_NET, "multiple Location headers");
+ if (git_net_url_apply_redirect(&transport->server.url, response->location, stream->service->url) < 0) {
return -1;
}
- t->location = git__strdup(git_buf_cstr(value));
- GIT_ERROR_CHECK_ALLOC(t->location);
- }
-
- return 0;
-}
-
-static int on_header_field(http_parser *parser, const char *str, size_t len)
-{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
-
- /* Both parse_header_name and parse_header_value are populated
- * and ready for consumption */
- if (VALUE == t->last_cb)
- if (on_header_ready(t) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- if (NONE == t->last_cb || VALUE == t->last_cb)
- git_buf_clear(&t->parse_header_name);
-
- if (git_buf_put(&t->parse_header_name, str, len) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- t->last_cb = FIELD;
- return 0;
-}
-
-static int on_header_value(http_parser *parser, const char *str, size_t len)
-{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
-
- assert(NONE != t->last_cb);
-
- if (FIELD == t->last_cb)
- git_buf_clear(&t->parse_header_value);
-
- if (git_buf_put(&t->parse_header_value, str, len) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- t->last_cb = VALUE;
- return 0;
-}
-
-GIT_INLINE(void) free_cred(git_cred **cred)
-{
- if (*cred) {
- git_cred_free(*cred);
- (*cred) = NULL;
- }
-}
-
-static int on_auth_required(
- git_cred **creds,
- http_parser *parser,
- const char *url,
- const char *type,
- git_cred_acquire_cb callback,
- void *callback_payload,
- const char *username,
- int allowed_types)
-{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
- int ret;
-
- if (!allowed_types) {
- git_error_set(GIT_ERROR_NET, "%s requested authentication but did not negotiate mechanisms", type);
- t->parse_error = PARSE_ERROR_GENERIC;
- return t->parse_error;
- }
-
- if (callback) {
- free_cred(creds);
- ret = callback(creds, url, username, allowed_types, callback_payload);
-
- if (ret == GIT_PASSTHROUGH) {
- /* treat GIT_PASSTHROUGH as if callback isn't set */
- } else if (ret < 0) {
- t->error = ret;
- t->parse_error = PARSE_ERROR_EXT;
- return t->parse_error;
- } else {
- assert(*creds);
-
- if (!((*creds)->credtype & allowed_types)) {
- git_error_set(GIT_ERROR_NET, "%s credential provider returned an invalid cred type", type);
- t->parse_error = PARSE_ERROR_GENERIC;
- return t->parse_error;
- }
-
- /* Successfully acquired a credential. */
- t->parse_error = PARSE_ERROR_REPLAY;
- return 0;
- }
+ return 0;
+ } else if (git_http_response_is_redirect(response)) {
+ git_error_set(GIT_ERROR_HTTP, "unexpected redirect");
+ return -1;
}
- git_error_set(GIT_ERROR_NET, "%s authentication required but no callback set",
- type);
- t->parse_error = PARSE_ERROR_GENERIC;
- return t->parse_error;
-}
-
-static int on_headers_complete(http_parser *parser)
-{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
- http_stream *s = ctx->s;
- git_buf buf = GIT_BUF_INIT;
- int proxy_auth_types = 0, server_auth_types = 0;
-
- /* Enforce a reasonable cap on the number of replays */
- if (t->replay_count++ >= GIT_HTTP_REPLAY_MAX) {
- git_error_set(GIT_ERROR_NET, "too many redirects or authentication replays");
- return t->parse_error = PARSE_ERROR_GENERIC;
- }
+ /* If we're in the middle of challenge/response auth, continue. */
+ if (allow_replay && response->resend_credentials) {
+ return 0;
+ } else if (allow_replay && response->status == GIT_HTTP_STATUS_UNAUTHORIZED) {
+ if ((error = handle_remote_auth(stream, response)) < 0)
+ return error;
- /* Both parse_header_name and parse_header_value are populated
- * and ready for consumption. */
- if (VALUE == t->last_cb)
- if (on_header_ready(t) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
+ return git_http_client_skip_body(transport->http_client);
+ } else if (allow_replay && response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+ if ((error = handle_proxy_auth(stream, response)) < 0)
+ return error;
- /*
- * Capture authentication headers for the proxy or final endpoint,
- * these may be 407/401 (authentication is not complete) or a 200
- * (informing us that auth has completed).
- */
- if (parse_authenticate_response(&t->proxy, &proxy_auth_types) < 0 ||
- parse_authenticate_response(&t->server, &server_auth_types) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- /* Check for a proxy authentication failure. */
- if (parser->status_code == 407 && get_verb == s->verb)
- return on_auth_required(&t->proxy.cred,
- parser,
- t->proxy_opts.url,
- SERVER_TYPE_PROXY,
- t->proxy_opts.credentials,
- t->proxy_opts.payload,
- t->proxy.url.user,
- proxy_auth_types);
-
- /* Check for an authentication failure. */
- if (parser->status_code == 401 && get_verb == s->verb)
- return on_auth_required(&t->server.cred,
- parser,
- t->owner->url,
- SERVER_TYPE_REMOTE,
- t->owner->cred_acquire_cb,
- t->owner->cred_acquire_payload,
- t->server.url.user,
- server_auth_types);
-
- /* Check for a redirect.
- * Right now we only permit a redirect to the same hostname. */
- if ((parser->status_code == 301 ||
- parser->status_code == 302 ||
- (parser->status_code == 303 && get_verb == s->verb) ||
- parser->status_code == 307 ||
- parser->status_code == 308) &&
- t->location) {
-
- if (gitno_connection_data_from_url(&t->server.url, t->location, s->service_url) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- /* Set the redirect URL on the stream. This is a transfer of
- * ownership of the memory. */
- if (s->redirect_url)
- git__free(s->redirect_url);
-
- s->redirect_url = t->location;
- t->location = NULL;
-
- t->connected = 0;
- t->parse_error = PARSE_ERROR_REPLAY;
- return 0;
+ return git_http_client_skip_body(transport->http_client);
+ } else if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED ||
+ response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+ git_error_set(GIT_ERROR_HTTP, "unexpected authentication failure");
+ return -1;
}
- /* Check for a 200 HTTP status code. */
- if (parser->status_code != 200) {
- git_error_set(GIT_ERROR_NET,
- "unexpected HTTP status code: %d",
- parser->status_code);
- return t->parse_error = PARSE_ERROR_GENERIC;
+ if (response->status != GIT_HTTP_STATUS_OK) {
+ git_error_set(GIT_ERROR_HTTP, "unexpected http status code: %d", response->status);
+ return -1;
}
/* The response must contain a Content-Type header. */
- if (!t->content_type) {
- git_error_set(GIT_ERROR_NET, "no Content-Type header in response");
- return t->parse_error = PARSE_ERROR_GENERIC;
+ if (!response->content_type) {
+ git_error_set(GIT_ERROR_HTTP, "no content-type header in response");
+ return -1;
}
/* The Content-Type header must match our expectation. */
- if (get_verb == s->verb)
- git_buf_printf(&buf,
- "application/x-git-%s-advertisement",
- ctx->s->service);
- else
- git_buf_printf(&buf,
- "application/x-git-%s-result",
- ctx->s->service);
-
- if (git_buf_oom(&buf))
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- if (strcmp(t->content_type, git_buf_cstr(&buf))) {
- git_buf_dispose(&buf);
- git_error_set(GIT_ERROR_NET,
- "invalid Content-Type: %s",
- t->content_type);
- return t->parse_error = PARSE_ERROR_GENERIC;
+ if (strcmp(response->content_type, stream->service->response_type) != 0) {
+ git_error_set(GIT_ERROR_HTTP, "invalid content-type: '%s'", response->content_type);
+ return -1;
}
- git_buf_dispose(&buf);
-
+ *complete = true;
+ stream->state = HTTP_STATE_RECEIVING_RESPONSE;
return 0;
}
-static int on_message_complete(http_parser *parser)
+static int lookup_proxy(
+ bool *out_use,
+ http_subtransport *transport)
{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
+ const char *proxy;
+ git_remote *remote;
+ bool use_ssl;
+ char *config = NULL;
+ int error = 0;
- t->parse_finished = 1;
+ *out_use = false;
+ git_net_url_dispose(&transport->proxy.url);
- return 0;
-}
-
-static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
-{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
-
- /* If our goal is to replay the request (either an auth failure or
- * a redirect) then don't bother buffering since we're ignoring the
- * content anyway.
- */
- if (t->parse_error == PARSE_ERROR_REPLAY)
- return 0;
-
- /* If there's no buffer set, we're explicitly ignoring the body. */
- if (ctx->buffer) {
- if (ctx->buf_size < len) {
- git_error_set(GIT_ERROR_NET, "can't fit data in the buffer");
- return t->parse_error = PARSE_ERROR_GENERIC;
- }
-
- memcpy(ctx->buffer, str, len);
- ctx->buffer += len;
- ctx->buf_size -= len;
- }
-
- *(ctx->bytes_read) += len;
-
- return 0;
-}
+ switch (transport->owner->proxy.type) {
+ case GIT_PROXY_SPECIFIED:
+ proxy = transport->owner->proxy.url;
+ break;
-static void clear_parser_state(http_subtransport *t)
-{
- http_parser_init(&t->parser, HTTP_RESPONSE);
- gitno_buffer_setup_fromstream(t->server.stream,
- &t->parse_buffer,
- t->parse_buffer_data,
- sizeof(t->parse_buffer_data));
+ case GIT_PROXY_AUTO:
+ remote = transport->owner->owner;
+ use_ssl = !strcmp(transport->server.url.scheme, "https");
- t->last_cb = NONE;
- t->parse_error = 0;
- t->parse_finished = 0;
+ error = git_remote__get_http_proxy(remote, use_ssl, &config);
- git_buf_dispose(&t->parse_header_name);
- git_buf_init(&t->parse_header_name, 0);
+ if (error || !config)
+ goto done;
- git_buf_dispose(&t->parse_header_value);
- git_buf_init(&t->parse_header_value, 0);
+ proxy = config;
+ break;
- git__free(t->content_type);
- t->content_type = NULL;
+ default:
+ return 0;
+ }
- git__free(t->content_length);
- t->content_length = NULL;
+ if (!proxy ||
+ (error = git_net_url_parse(&transport->proxy.url, proxy)) < 0)
+ goto done;
- git__free(t->location);
- t->location = NULL;
+ *out_use = true;
- git_vector_free_deep(&t->proxy.auth_challenges);
- git_vector_free_deep(&t->server.auth_challenges);
+done:
+ git__free(config);
+ return error;
}
-static int write_chunk(git_stream *io, const char *buffer, size_t len)
+static int generate_request(
+ git_net_url *url,
+ git_http_request *request,
+ http_stream *stream,
+ size_t len)
{
- git_buf buf = GIT_BUF_INIT;
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
+ bool use_proxy = false;
+ int error;
- /* Chunk header */
- git_buf_printf(&buf, "%" PRIxZ "\r\n", len);
+ if ((error = git_net_url_joinpath(url,
+ &transport->server.url, stream->service->url)) < 0 ||
+ (error = lookup_proxy(&use_proxy, transport)) < 0)
+ return error;
- if (git_buf_oom(&buf))
- return -1;
+ request->method = stream->service->method;
+ request->url = url;
+ request->credentials = transport->server.cred;
+ request->proxy = use_proxy ? &transport->proxy.url : NULL;
+ request->proxy_credentials = transport->proxy.cred;
+ request->custom_headers = &transport->owner->custom_headers;
- if (git_stream__write_full(io, buf.ptr, buf.size, 0) < 0) {
- git_buf_dispose(&buf);
- return -1;
+ if (stream->service->method == GIT_HTTP_METHOD_POST) {
+ request->chunked = stream->service->chunked;
+ request->content_length = stream->service->chunked ? 0 : len;
+ request->content_type = stream->service->request_type;
+ request->accept = stream->service->response_type;
+ request->expect_continue = git_http__expect_continue;
}
- git_buf_dispose(&buf);
-
- /* Chunk body */
- if (len > 0 && git_stream__write_full(io, buffer, len, 0) < 0)
- return -1;
-
- /* Chunk footer */
- if (git_stream__write_full(io, "\r\n", 2, 0) < 0)
- return -1;
-
return 0;
}
-static int load_proxy_config(http_subtransport *t)
-{
+/*
+ * Read from an HTTP transport - for the first invocation of this function
+ * (ie, when stream->state == HTTP_STATE_NONE), we'll send a GET request
+ * to the remote host. We will stream that data back on all subsequent
+ * calls.
+ */
+static int http_stream_read(
+ git_smart_subtransport_stream *s,
+ char *buffer,
+ size_t buffer_size,
+ size_t *out_len)
+{
+ http_stream *stream = (http_stream *)s;
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
+ git_net_url url = GIT_NET_URL_INIT;
+ git_net_url proxy_url = GIT_NET_URL_INIT;
+ git_http_request request = {0};
+ git_http_response response = {0};
+ bool complete;
int error;
- switch (t->owner->proxy.type) {
- case GIT_PROXY_NONE:
- return 0;
-
- case GIT_PROXY_AUTO:
- git__free(t->proxy_url);
- t->proxy_url = NULL;
-
- git_proxy_init_options(&t->proxy_opts, GIT_PROXY_OPTIONS_VERSION);
+ *out_len = 0;
- if ((error = git_remote__get_http_proxy(t->owner->owner,
- !!t->server.url.use_ssl, &t->proxy_url)) < 0)
- return error;
-
- if (!t->proxy_url)
- return 0;
+ if (stream->state == HTTP_STATE_NONE) {
+ stream->state = HTTP_STATE_SENDING_REQUEST;
+ stream->replay_count = 0;
+ }
- t->proxy_opts.type = GIT_PROXY_SPECIFIED;
- t->proxy_opts.url = t->proxy_url;
- t->proxy_opts.credentials = t->owner->proxy.credentials;
- t->proxy_opts.certificate_check = t->owner->proxy.certificate_check;
- t->proxy_opts.payload = t->owner->proxy.payload;
- break;
+ /*
+ * Formulate the URL, send the request and read the response
+ * headers. Some of the request body may also be read.
+ */
+ while (stream->state == HTTP_STATE_SENDING_REQUEST &&
+ stream->replay_count < GIT_HTTP_REPLAY_MAX) {
+ git_net_url_dispose(&url);
+ git_net_url_dispose(&proxy_url);
+ git_http_response_dispose(&response);
+
+ if ((error = generate_request(&url, &request, stream, 0)) < 0 ||
+ (error = git_http_client_send_request(
+ transport->http_client, &request)) < 0 ||
+ (error = git_http_client_read_response(
+ &response, transport->http_client)) < 0 ||
+ (error = handle_response(&complete, stream, &response, true)) < 0)
+ goto done;
- case GIT_PROXY_SPECIFIED:
- memcpy(&t->proxy_opts, &t->owner->proxy, sizeof(git_proxy_options));
- break;
+ if (complete)
+ break;
- default:
- assert(0);
- return -1;
+ stream->replay_count++;
}
- if ((error = gitno_connection_data_from_url(&t->proxy.url, t->proxy_opts.url, NULL)) < 0)
- return error;
-
- if (t->proxy.url.use_ssl) {
- git_error_set(GIT_ERROR_NET, "SSL connections to proxy are not supported");
- return -1;
+ if (stream->state == HTTP_STATE_SENDING_REQUEST) {
+ git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays");
+ error = -1;
+ goto done;
}
- return error;
-}
-
-static int check_certificate(
- git_stream *stream,
- gitno_connection_data *url,
- int is_valid,
- git_transport_certificate_check_cb cert_cb,
- void *cert_cb_payload)
-{
- git_cert *cert;
- git_error_state last_error = {0};
- int error;
-
- if ((error = git_stream_certificate(&cert, stream)) < 0)
- return error;
-
- git_error_state_capture(&last_error, GIT_ECERTIFICATE);
+ assert (stream->state == HTTP_STATE_RECEIVING_RESPONSE);
- error = cert_cb(cert, is_valid, url->host, cert_cb_payload);
+ error = git_http_client_read_body(transport->http_client, buffer, buffer_size);
- if (error == GIT_PASSTHROUGH && !is_valid)
- return git_error_state_restore(&last_error);
- else if (error == GIT_PASSTHROUGH)
+ if (error > 0) {
+ *out_len = error;
error = 0;
- else if (error && !git_error_last())
- git_error_set(GIT_ERROR_NET, "user rejected certificate for %s", url->host);
-
- git_error_state_free(&last_error);
- return error;
-}
-
-static int stream_connect(
- git_stream *stream,
- gitno_connection_data *url,
- git_transport_certificate_check_cb cert_cb,
- void *cb_payload)
-{
- int error;
-
- GIT_ERROR_CHECK_VERSION(stream, GIT_STREAM_VERSION, "git_stream");
-
- error = git_stream_connect(stream);
-
- if (error && error != GIT_ECERTIFICATE)
- return error;
+ }
- if (git_stream_is_encrypted(stream) && cert_cb != NULL)
- error = check_certificate(stream, url, !error, cert_cb, cb_payload);
+done:
+ git_net_url_dispose(&url);
+ git_net_url_dispose(&proxy_url);
+ git_http_response_dispose(&response);
return error;
}
-static int gen_connect_req(git_buf *buf, http_subtransport *t)
+static bool needs_probe(http_stream *stream)
{
- git_buf_printf(buf, "CONNECT %s:%s HTTP/1.1\r\n",
- t->server.url.host, t->server.url.port);
-
- git_buf_puts(buf, "User-Agent: ");
- git_http__user_agent(buf);
- git_buf_puts(buf, "\r\n");
-
- git_buf_printf(buf, "Host: %s\r\n", t->proxy.url.host);
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
- if (apply_credentials(buf, &t->proxy, AUTH_HEADER_PROXY) < 0)
- return -1;
-
- git_buf_puts(buf, "\r\n");
-
- return git_buf_oom(buf) ? -1 : 0;
+ return (transport->server.auth_schemetypes == GIT_HTTP_AUTH_NTLM ||
+ transport->server.auth_schemetypes == GIT_HTTP_AUTH_NEGOTIATE);
}
-static int proxy_headers_complete(http_parser *parser)
+static int send_probe(http_stream *stream)
{
- parser_context *ctx = (parser_context *) parser->data;
- http_subtransport *t = ctx->t;
- int proxy_auth_types = 0;
-
- /* Enforce a reasonable cap on the number of replays */
- if (t->replay_count++ >= GIT_HTTP_REPLAY_MAX) {
- git_error_set(GIT_ERROR_NET, "too many redirects or authentication replays");
- return t->parse_error = PARSE_ERROR_GENERIC;
- }
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
+ git_http_client *client = transport->http_client;
+ const char *probe = "0000";
+ size_t len = 4;
+ git_net_url url = GIT_NET_URL_INIT;
+ git_http_request request = {0};
+ git_http_response response = {0};
+ bool complete = false;
+ size_t step, steps = 1;
+ int error;
- /* Both parse_header_name and parse_header_value are populated
- * and ready for consumption. */
- if (VALUE == t->last_cb)
- if (on_header_ready(t) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
+ /* NTLM requires a full challenge/response */
+ if (transport->server.auth_schemetypes == GIT_HTTP_AUTH_NTLM)
+ steps = GIT_AUTH_STEPS_NTLM;
/*
- * Capture authentication headers for the proxy or final endpoint,
- * these may be 407/401 (authentication is not complete) or a 200
- * (informing us that auth has completed).
+ * Send at most two requests: one without any authentication to see
+ * if we get prompted to authenticate. If we do, send a second one
+ * with the first authentication message. The final authentication
+ * message with the response will occur with the *actual* POST data.
*/
- if (parse_authenticate_response(&t->proxy, &proxy_auth_types) < 0)
- return t->parse_error = PARSE_ERROR_GENERIC;
-
- /* Check for a proxy authentication failure. */
- if (parser->status_code == 407)
- return on_auth_required(&t->proxy.cred,
- parser,
- t->proxy_opts.url,
- SERVER_TYPE_PROXY,
- t->proxy_opts.credentials,
- t->proxy_opts.payload,
- t->proxy.url.user,
- proxy_auth_types);
-
- if (parser->status_code != 200) {
- git_error_set(GIT_ERROR_NET, "unexpected status code from proxy: %d",
- parser->status_code);
- return t->parse_error = PARSE_ERROR_GENERIC;
+ for (step = 0; step < steps && !complete; step++) {
+ git_net_url_dispose(&url);
+ git_http_response_dispose(&response);
+
+ if ((error = generate_request(&url, &request, stream, len)) < 0 ||
+ (error = git_http_client_send_request(client, &request)) < 0 ||
+ (error = git_http_client_send_body(client, probe, len)) < 0 ||
+ (error = git_http_client_read_response(&response, client)) < 0 ||
+ (error = git_http_client_skip_body(client)) < 0 ||
+ (error = handle_response(&complete, stream, &response, true)) < 0)
+ goto done;
}
- if (!t->content_length || strcmp(t->content_length, "0") == 0)
- t->parse_finished = 1;
-
- return 0;
+done:
+ git_http_response_dispose(&response);
+ git_net_url_dispose(&url);
+ return error;
}
-static int proxy_connect(
- git_stream **out, git_stream *proxy_stream, http_subtransport *t)
+/*
+* Write to an HTTP transport - for the first invocation of this function
+* (ie, when stream->state == HTTP_STATE_NONE), we'll send a POST request
+* to the remote host. If we're sending chunked data, then subsequent calls
+* will write the additional data given in the buffer. If we're not chunking,
+* then the caller should have given us all the data in the original call.
+* The caller should call http_stream_read_response to get the result.
+*/
+static int http_stream_write(
+ git_smart_subtransport_stream *s,
+ const char *buffer,
+ size_t len)
{
- git_buf request = GIT_BUF_INIT;
- static http_parser_settings proxy_parser_settings = {0};
- size_t bytes_read = 0, bytes_parsed;
- parser_context ctx;
+ http_stream *stream = GIT_CONTAINER_OF(s, http_stream, parent);
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
+ git_net_url url = GIT_NET_URL_INIT;
+ git_http_request request = {0};
+ git_http_response response = {0};
int error;
- /* Use the parser settings only to parser headers. */
- proxy_parser_settings.on_header_field = on_header_field;
- proxy_parser_settings.on_header_value = on_header_value;
- proxy_parser_settings.on_headers_complete = proxy_headers_complete;
- proxy_parser_settings.on_message_complete = on_message_complete;
-
-replay:
- clear_parser_state(t);
-
- gitno_buffer_setup_fromstream(proxy_stream,
- &t->parse_buffer,
- t->parse_buffer_data,
- sizeof(t->parse_buffer_data));
+ while (stream->state == HTTP_STATE_NONE &&
+ stream->replay_count < GIT_HTTP_REPLAY_MAX) {
- if ((error = gen_connect_req(&request, t)) < 0)
- goto done;
-
- if ((error = git_stream__write_full(proxy_stream, request.ptr,
- request.size, 0)) < 0)
- goto done;
-
- git_buf_dispose(&request);
-
- while (!bytes_read && !t->parse_finished) {
- t->parse_buffer.offset = 0;
-
- if ((error = gitno_recv(&t->parse_buffer)) < 0)
- goto done;
+ git_net_url_dispose(&url);
+ git_http_response_dispose(&response);
/*
- * This call to http_parser_execute will invoke the on_*
- * callbacks. Since we don't care about the body of the response,
- * we can set our buffer to NULL.
+ * If we're authenticating with a connection-based mechanism
+ * (NTLM, Kerberos), send a "probe" packet. Servers SHOULD
+ * authenticate an entire keep-alive connection, so ideally
+ * we should not need to authenticate but some servers do
+ * not support this. By sending a probe packet, we'll be
+ * able to follow up with a second POST using the actual
+ * data (and, in the degenerate case, the authentication
+ * header as well).
*/
- ctx.t = t;
- ctx.s = NULL;
- ctx.buffer = NULL;
- ctx.buf_size = 0;
- ctx.bytes_read = &bytes_read;
-
- /* Set the context, call the parser, then unset the context. */
- t->parser.data = &ctx;
-
- bytes_parsed = http_parser_execute(&t->parser,
- &proxy_parser_settings, t->parse_buffer.data, t->parse_buffer.offset);
-
- t->parser.data = NULL;
-
- /* Ensure that we didn't get a redirect; unsupported. */
- if (t->location) {
- git_error_set(GIT_ERROR_NET, "proxy server sent unsupported redirect during CONNECT");
- error = -1;
+ if (needs_probe(stream) && (error = send_probe(stream)) < 0)
goto done;
- }
-
- /* Replay the request with authentication headers. */
- if (PARSE_ERROR_REPLAY == t->parse_error)
- goto replay;
- if (t->parse_error < 0) {
- error = t->parse_error == PARSE_ERROR_EXT ? PARSE_ERROR_EXT : -1;
+ /* Send the regular POST request. */
+ if ((error = generate_request(&url, &request, stream, len)) < 0 ||
+ (error = git_http_client_send_request(
+ transport->http_client, &request)) < 0)
goto done;
- }
- if (bytes_parsed != t->parse_buffer.offset) {
- git_error_set(GIT_ERROR_NET,
- "HTTP parser error: %s",
- http_errno_description((enum http_errno)t->parser.http_errno));
- error = -1;
- goto done;
+ if (request.expect_continue &&
+ git_http_client_has_response(transport->http_client)) {
+ bool complete;
+
+ /*
+ * If we got a response to an expect/continue, then
+ * it's something other than a 100 and we should
+ * deal with the response somehow.
+ */
+ if ((error = git_http_client_read_response(&response, transport->http_client)) < 0 ||
+ (error = handle_response(&complete, stream, &response, true)) < 0)
+ goto done;
+ } else {
+ stream->state = HTTP_STATE_SENDING_REQUEST;
}
- }
-
- if ((error = git_tls_stream_wrap(out, proxy_stream, t->server.url.host)) == 0)
- error = stream_connect(*out, &t->server.url,
- t->owner->certificate_check_cb,
- t->owner->message_cb_payload);
-
- /*
- * Since we've connected via a HTTPS proxy tunnel, we don't behave
- * as if we have an HTTP proxy.
- */
- t->proxy_opts.type = GIT_PROXY_NONE;
- t->replay_count = 0;
-done:
- return error;
-}
-
-static int http_connect(http_subtransport *t)
-{
- gitno_connection_data *url;
- git_stream *proxy_stream = NULL, *stream = NULL;
- git_transport_certificate_check_cb cert_cb;
- void *cb_payload;
- int error;
-
- if (t->connected &&
- http_should_keep_alive(&t->parser) &&
- t->parse_finished)
- return 0;
-
- if ((error = load_proxy_config(t)) < 0)
- return error;
-
- if (t->server.stream) {
- git_stream_close(t->server.stream);
- git_stream_free(t->server.stream);
- t->server.stream = NULL;
- }
-
- if (t->proxy.stream) {
- git_stream_close(t->proxy.stream);
- git_stream_free(t->proxy.stream);
- t->proxy.stream = NULL;
- }
-
- t->connected = 0;
-
- if (t->proxy_opts.type == GIT_PROXY_SPECIFIED) {
- url = &t->proxy.url;
- cert_cb = t->proxy_opts.certificate_check;
- cb_payload = t->proxy_opts.payload;
- } else {
- url = &t->server.url;
- cert_cb = t->owner->certificate_check_cb;
- cb_payload = t->owner->message_cb_payload;
+ stream->replay_count++;
}
- if (url->use_ssl)
- error = git_tls_stream_new(&stream, url->host, url->port);
- else
- error = git_socket_stream_new(&stream, url->host, url->port);
-
- if (error < 0)
- goto on_error;
-
- if ((error = stream_connect(stream, url, cert_cb, cb_payload)) < 0)
- goto on_error;
-
- /*
- * At this point we have a connection to the remote server or to
- * a proxy. If it's a proxy and the remote server is actually
- * an HTTPS connection, then we need to build a CONNECT tunnel.
- */
- if (t->proxy_opts.type == GIT_PROXY_SPECIFIED &&
- t->server.url.use_ssl) {
- proxy_stream = stream;
- stream = NULL;
-
- if ((error = proxy_connect(&stream, proxy_stream, t)) < 0)
- goto on_error;
+ if (stream->state == HTTP_STATE_NONE) {
+ git_error_set(GIT_ERROR_HTTP,
+ "too many redirects or authentication replays");
+ error = -1;
+ goto done;
}
- t->proxy.stream = proxy_stream;
- t->server.stream = stream;
- t->connected = 1;
- t->replay_count = 0;
- return 0;
+ assert(stream->state == HTTP_STATE_SENDING_REQUEST);
-on_error:
- if (stream) {
- git_stream_close(stream);
- git_stream_free(stream);
- }
-
- if (proxy_stream) {
- git_stream_close(proxy_stream);
- git_stream_free(proxy_stream);
- }
+ error = git_http_client_send_body(transport->http_client, buffer, len);
+done:
+ git_http_response_dispose(&response);
+ git_net_url_dispose(&url);
return error;
}
-static int http_stream_read(
- git_smart_subtransport_stream *stream,
+/*
+* Read from an HTTP transport after it has been written to. This is the
+* response from a POST request made by http_stream_write.
+*/
+static int http_stream_read_response(
+ git_smart_subtransport_stream *s,
char *buffer,
- size_t buf_size,
- size_t *bytes_read)
-{
- http_stream *s = (http_stream *)stream;
- http_subtransport *t = OWNING_SUBTRANSPORT(s);
- parser_context ctx;
- size_t bytes_parsed;
-
-replay:
- *bytes_read = 0;
-
- assert(t->connected);
-
- if (!s->sent_request) {
- git_buf request = GIT_BUF_INIT;
-
- clear_parser_state(t);
-
- if (gen_request(&request, s, 0) < 0)
- return -1;
-
- if (git_stream__write_full(t->server.stream, request.ptr,
- request.size, 0) < 0) {
- git_buf_dispose(&request);
- return -1;
- }
-
- git_buf_dispose(&request);
-
- s->sent_request = 1;
- }
-
- if (!s->received_response) {
- if (s->chunked) {
- assert(s->verb == post_verb);
-
- /* Flush, if necessary */
- if (s->chunk_buffer_len > 0 &&
- write_chunk(t->server.stream,
- s->chunk_buffer, s->chunk_buffer_len) < 0)
- return -1;
-
- s->chunk_buffer_len = 0;
-
- /* Write the final chunk. */
- if (git_stream__write_full(t->server.stream,
- "0\r\n\r\n", 5, 0) < 0)
- return -1;
- }
-
- s->received_response = 1;
- }
-
- while (!*bytes_read && !t->parse_finished) {
- size_t data_offset;
- int error;
-
- /*
- * Make the parse_buffer think it's as full of data as
- * the buffer, so it won't try to recv more data than
- * we can put into it.
- *
- * data_offset is the actual data offset from which we
- * should tell the parser to start reading.
- */
- if (buf_size >= t->parse_buffer.len) {
- t->parse_buffer.offset = 0;
- } else {
- t->parse_buffer.offset = t->parse_buffer.len - buf_size;
- }
-
- data_offset = t->parse_buffer.offset;
-
- if (gitno_recv(&t->parse_buffer) < 0)
- return -1;
-
- /* This call to http_parser_execute will result in invocations of the
- * on_* family of callbacks. The most interesting of these is
- * on_body_fill_buffer, which is called when data is ready to be copied
- * into the target buffer. We need to marshal the buffer, buf_size, and
- * bytes_read parameters to this callback. */
- ctx.t = t;
- ctx.s = s;
- ctx.buffer = buffer;
- ctx.buf_size = buf_size;
- ctx.bytes_read = bytes_read;
-
- /* Set the context, call the parser, then unset the context. */
- t->parser.data = &ctx;
-
- bytes_parsed = http_parser_execute(&t->parser,
- &t->settings,
- t->parse_buffer.data + data_offset,
- t->parse_buffer.offset - data_offset);
-
- t->parser.data = NULL;
-
- /* If there was a handled authentication failure, then parse_error
- * will have signaled us that we should replay the request. */
- if (PARSE_ERROR_REPLAY == t->parse_error) {
- s->sent_request = 0;
-
- if ((error = http_connect(t)) < 0)
- return error;
-
- goto replay;
- }
-
- if (t->parse_error == PARSE_ERROR_EXT) {
- return t->error;
- }
-
- if (t->parse_error < 0)
- return -1;
-
- if (bytes_parsed != t->parse_buffer.offset - data_offset) {
- git_error_set(GIT_ERROR_NET,
- "HTTP parser error: %s",
- http_errno_description((enum http_errno)t->parser.http_errno));
- return -1;
- }
- }
-
- return 0;
-}
-
-static int http_stream_write_chunked(
- git_smart_subtransport_stream *stream,
- const char *buffer,
- size_t len)
-{
- http_stream *s = (http_stream *)stream;
- http_subtransport *t = OWNING_SUBTRANSPORT(s);
-
- assert(t->connected);
-
- /* Send the request, if necessary */
- if (!s->sent_request) {
- git_buf request = GIT_BUF_INIT;
-
- clear_parser_state(t);
-
- if (gen_request(&request, s, 0) < 0)
- return -1;
+ size_t buffer_size,
+ size_t *out_len)
+{
+ http_stream *stream = (http_stream *)s;
+ http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
+ git_http_client *client = transport->http_client;
+ git_http_response response = {0};
+ bool complete;
+ int error;
- if (git_stream__write_full(t->server.stream, request.ptr,
- request.size, 0) < 0) {
- git_buf_dispose(&request);
- return -1;
- }
+ *out_len = 0;
- git_buf_dispose(&request);
+ if (stream->state == HTTP_STATE_SENDING_REQUEST) {
+ if ((error = git_http_client_read_response(&response, client)) < 0 ||
+ (error = handle_response(&complete, stream, &response, false)) < 0)
+ goto done;
- s->sent_request = 1;
+ assert(complete);
+ stream->state = HTTP_STATE_RECEIVING_RESPONSE;
}
- if (len > CHUNK_SIZE) {
- /* Flush, if necessary */
- if (s->chunk_buffer_len > 0) {
- if (write_chunk(t->server.stream,
- s->chunk_buffer, s->chunk_buffer_len) < 0)
- return -1;
-
- s->chunk_buffer_len = 0;
- }
+ error = git_http_client_read_body(client, buffer, buffer_size);
- /* Write chunk directly */
- if (write_chunk(t->server.stream, buffer, len) < 0)
- return -1;
- }
- else {
- /* Append as much to the buffer as we can */
- int count = min(CHUNK_SIZE - s->chunk_buffer_len, len);
-
- if (!s->chunk_buffer)
- s->chunk_buffer = git__malloc(CHUNK_SIZE);
-
- memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count);
- s->chunk_buffer_len += count;
- buffer += count;
- len -= count;
-
- /* Is the buffer full? If so, then flush */
- if (CHUNK_SIZE == s->chunk_buffer_len) {
- if (write_chunk(t->server.stream,
- s->chunk_buffer, s->chunk_buffer_len) < 0)
- return -1;
-
- s->chunk_buffer_len = 0;
-
- if (len > 0) {
- memcpy(s->chunk_buffer, buffer, len);
- s->chunk_buffer_len = len;
- }
- }
- }
-
- return 0;
-}
-
-static int http_stream_write_single(
- git_smart_subtransport_stream *stream,
- const char *buffer,
- size_t len)
-{
- http_stream *s = (http_stream *)stream;
- http_subtransport *t = OWNING_SUBTRANSPORT(s);
- git_buf request = GIT_BUF_INIT;
-
- assert(t->connected);
-
- if (s->sent_request) {
- git_error_set(GIT_ERROR_NET, "subtransport configured for only one write");
- return -1;
+ if (error > 0) {
+ *out_len = error;
+ error = 0;
}
- clear_parser_state(t);
-
- if (gen_request(&request, s, len) < 0)
- return -1;
-
- if (git_stream__write_full(t->server.stream, request.ptr, request.size, 0) < 0)
- goto on_error;
-
- if (len && git_stream__write_full(t->server.stream, buffer, len, 0) < 0)
- goto on_error;
-
- git_buf_dispose(&request);
- s->sent_request = 1;
-
- return 0;
-
-on_error:
- git_buf_dispose(&request);
- return -1;
+done:
+ git_http_response_dispose(&response);
+ return error;
}
static void http_stream_free(git_smart_subtransport_stream *stream)
{
- http_stream *s = (http_stream *)stream;
-
- if (s->chunk_buffer)
- git__free(s->chunk_buffer);
-
- if (s->redirect_url)
- git__free(s->redirect_url);
-
+ http_stream *s = GIT_CONTAINER_OF(stream, http_stream, parent);
git__free(s);
}
-static int http_stream_alloc(http_subtransport *t,
- git_smart_subtransport_stream **stream)
-{
- http_stream *s;
-
- if (!stream)
- return -1;
-
- s = git__calloc(sizeof(http_stream), 1);
- GIT_ERROR_CHECK_ALLOC(s);
-
- s->parent.subtransport = &t->parent;
- s->parent.read = http_stream_read;
- s->parent.write = http_stream_write_single;
- s->parent.free = http_stream_free;
-
- *stream = (git_smart_subtransport_stream *)s;
- return 0;
-}
-
-static int http_uploadpack_ls(
- http_subtransport *t,
- git_smart_subtransport_stream **stream)
-{
- http_stream *s;
-
- if (http_stream_alloc(t, stream) < 0)
- return -1;
-
- s = (http_stream *)*stream;
-
- s->service = upload_pack_service;
- s->service_url = upload_pack_ls_service_url;
- s->verb = get_verb;
-
- return 0;
-}
-
-static int http_uploadpack(
- http_subtransport *t,
- git_smart_subtransport_stream **stream)
+static const http_service *select_service(git_smart_service_t action)
{
- http_stream *s;
-
- if (http_stream_alloc(t, stream) < 0)
- return -1;
-
- s = (http_stream *)*stream;
-
- s->service = upload_pack_service;
- s->service_url = upload_pack_service_url;
- s->verb = post_verb;
-
- return 0;
-}
-
-static int http_receivepack_ls(
- http_subtransport *t,
- git_smart_subtransport_stream **stream)
-{
- http_stream *s;
-
- if (http_stream_alloc(t, stream) < 0)
- return -1;
-
- s = (http_stream *)*stream;
-
- s->service = receive_pack_service;
- s->service_url = receive_pack_ls_service_url;
- s->verb = get_verb;
-
- return 0;
-}
-
-static int http_receivepack(
- http_subtransport *t,
- git_smart_subtransport_stream **stream)
-{
- http_stream *s;
-
- if (http_stream_alloc(t, stream) < 0)
- return -1;
-
- s = (http_stream *)*stream;
-
- /* Use Transfer-Encoding: chunked for this request */
- s->chunked = 1;
- s->parent.write = http_stream_write_chunked;
-
- s->service = receive_pack_service;
- s->service_url = receive_pack_service_url;
- s->verb = post_verb;
+ switch (action) {
+ case GIT_SERVICE_UPLOADPACK_LS:
+ return &upload_pack_ls_service;
+ case GIT_SERVICE_UPLOADPACK:
+ return &upload_pack_service;
+ case GIT_SERVICE_RECEIVEPACK_LS:
+ return &receive_pack_ls_service;
+ case GIT_SERVICE_RECEIVEPACK:
+ return &receive_pack_service;
+ }
- return 0;
+ return NULL;
}
static int http_action(
- git_smart_subtransport_stream **stream,
- git_smart_subtransport *subtransport,
+ git_smart_subtransport_stream **out,
+ git_smart_subtransport *t,
const char *url,
git_smart_service_t action)
{
- http_subtransport *t = (http_subtransport *)subtransport;
- int ret;
+ http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent);
+ http_stream *stream;
+ const http_service *service;
+ int error;
- assert(stream);
+ assert(out && t);
+
+ *out = NULL;
/*
* If we've seen a redirect then preserve the location that we've
* have redirected us from HTTP->HTTPS and is using an auth mechanism
* that would be insecure in plaintext (eg, HTTP Basic).
*/
- if ((!t->server.url.host || !t->server.url.port || !t->server.url.path) &&
- (ret = gitno_connection_data_from_url(&t->server.url, url, NULL)) < 0)
- return ret;
-
- assert(t->server.url.host && t->server.url.port && t->server.url.path);
+ if (!git_net_url_valid(&transport->server.url) &&
+ (error = git_net_url_parse(&transport->server.url, url)) < 0)
+ return error;
- if ((ret = http_connect(t)) < 0)
- return ret;
+ if ((service = select_service(action)) == NULL) {
+ git_error_set(GIT_ERROR_HTTP, "invalid action");
+ return -1;
+ }
- switch (action) {
- case GIT_SERVICE_UPLOADPACK_LS:
- return http_uploadpack_ls(t, stream);
+ stream = git__calloc(sizeof(http_stream), 1);
+ GIT_ERROR_CHECK_ALLOC(stream);
- case GIT_SERVICE_UPLOADPACK:
- return http_uploadpack(t, stream);
+ if (!transport->http_client) {
+ git_http_client_options opts = {0};
- case GIT_SERVICE_RECEIVEPACK_LS:
- return http_receivepack_ls(t, stream);
+ opts.server_certificate_check_cb = transport->owner->certificate_check_cb;
+ opts.server_certificate_check_payload = transport->owner->message_cb_payload;
+ opts.proxy_certificate_check_cb = transport->owner->proxy.certificate_check;
+ opts.proxy_certificate_check_payload = transport->owner->proxy.payload;
- case GIT_SERVICE_RECEIVEPACK:
- return http_receivepack(t, stream);
+ if (git_http_client_new(&transport->http_client, &opts) < 0)
+ return -1;
}
- *stream = NULL;
- return -1;
-}
-
-static void free_auth_contexts(git_vector *contexts)
-{
- git_http_auth_context *context;
- size_t i;
+ stream->service = service;
+ stream->parent.subtransport = &transport->parent;
- git_vector_foreach(contexts, i, context) {
- if (context->free)
- context->free(context);
+ if (service->method == GIT_HTTP_METHOD_GET) {
+ stream->parent.read = http_stream_read;
+ } else {
+ stream->parent.write = http_stream_write;
+ stream->parent.read = http_stream_read_response;
}
- git_vector_clear(contexts);
+ stream->parent.free = http_stream_free;
+
+ *out = (git_smart_subtransport_stream *)stream;
+ return 0;
}
-static int http_close(git_smart_subtransport *subtransport)
+static int http_close(git_smart_subtransport *t)
{
- http_subtransport *t = (http_subtransport *) subtransport;
-
- clear_parser_state(t);
-
- t->connected = 0;
-
- if (t->server.stream) {
- git_stream_close(t->server.stream);
- git_stream_free(t->server.stream);
- t->server.stream = NULL;
- }
-
- if (t->proxy.stream) {
- git_stream_close(t->proxy.stream);
- git_stream_free(t->proxy.stream);
- t->proxy.stream = NULL;
- }
-
- free_cred(&t->server.cred);
- free_cred(&t->server.url_cred);
- free_cred(&t->proxy.cred);
- free_cred(&t->proxy.url_cred);
+ http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent);
- free_auth_contexts(&t->server.auth_contexts);
- free_auth_contexts(&t->proxy.auth_contexts);
+ free_cred(&transport->server.cred);
+ free_cred(&transport->proxy.cred);
- gitno_connection_data_free_ptrs(&t->server.url);
- memset(&t->server.url, 0x0, sizeof(gitno_connection_data));
+ transport->server.url_cred_presented = false;
+ transport->proxy.url_cred_presented = false;
- gitno_connection_data_free_ptrs(&t->proxy.url);
- memset(&t->proxy.url, 0x0, sizeof(gitno_connection_data));
-
- git__free(t->proxy_url);
- t->proxy_url = NULL;
+ git_net_url_dispose(&transport->server.url);
+ git_net_url_dispose(&transport->proxy.url);
return 0;
}
-static void http_free(git_smart_subtransport *subtransport)
+static void http_free(git_smart_subtransport *t)
{
- http_subtransport *t = (http_subtransport *) subtransport;
+ http_subtransport *transport = GIT_CONTAINER_OF(t, http_subtransport, parent);
- http_close(subtransport);
+ git_http_client_free(transport->http_client);
- git_vector_free(&t->server.auth_contexts);
- git_vector_free(&t->proxy.auth_contexts);
- git__free(t);
+ http_close(t);
+ git__free(transport);
}
int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner, void *param)
{
- http_subtransport *t;
+ http_subtransport *transport;
GIT_UNUSED(param);
- if (!out)
- return -1;
-
- t = git__calloc(sizeof(http_subtransport), 1);
- GIT_ERROR_CHECK_ALLOC(t);
+ assert(out);
- t->owner = (transport_smart *)owner;
- t->parent.action = http_action;
- t->parent.close = http_close;
- t->parent.free = http_free;
+ transport = git__calloc(sizeof(http_subtransport), 1);
+ GIT_ERROR_CHECK_ALLOC(transport);
- t->settings.on_header_field = on_header_field;
- t->settings.on_header_value = on_header_value;
- t->settings.on_headers_complete = on_headers_complete;
- t->settings.on_body = on_body_fill_buffer;
- t->settings.on_message_complete = on_message_complete;
+ transport->owner = (transport_smart *)owner;
+ transport->parent.action = http_action;
+ transport->parent.close = http_close;
+ transport->parent.free = http_free;
- *out = (git_smart_subtransport *) t;
+ *out = (git_smart_subtransport *) transport;
return 0;
}
#define INCLUDE_transports_http_h__
#include "buffer.h"
+#include "httpclient.h"
-#define GIT_HTTP_REPLAY_MAX 7
+#define GIT_HTTP_REPLAY_MAX 15
+
+extern bool git_http__expect_continue;
GIT_INLINE(int) git_http__user_agent(git_buf *buf)
{
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+#include "git2.h"
+#include "http_parser.h"
+#include "vector.h"
+#include "trace.h"
+#include "global.h"
+#include "httpclient.h"
+#include "http.h"
+#include "auth.h"
+#include "auth_negotiate.h"
+#include "auth_ntlm.h"
+#include "git2/sys/credential.h"
+#include "net.h"
+#include "stream.h"
+#include "streams/socket.h"
+#include "streams/tls.h"
+#include "auth.h"
+
+static git_http_auth_scheme auth_schemes[] = {
+ { GIT_HTTP_AUTH_NEGOTIATE, "Negotiate", GIT_CREDENTIAL_DEFAULT, git_http_auth_negotiate },
+ { GIT_HTTP_AUTH_NTLM, "NTLM", GIT_CREDENTIAL_USERPASS_PLAINTEXT, git_http_auth_ntlm },
+ { GIT_HTTP_AUTH_BASIC, "Basic", GIT_CREDENTIAL_USERPASS_PLAINTEXT, git_http_auth_basic },
+};
+
+/*
+ * Use a 16kb read buffer to match the maximum size of a TLS packet. This
+ * is critical for compatibility with SecureTransport, which will always do
+ * a network read on every call, even if it has data buffered to return to
+ * you. That buffered data may be the _end_ of a keep-alive response, so
+ * if SecureTransport performs another network read, it will wait until the
+ * server ultimately times out before it returns that buffered data to you.
+ * Since SecureTransport only reads a single TLS packet at a time, by
+ * calling it with a read buffer that is the maximum size of a TLS packet,
+ * we ensure that it will never buffer.
+ */
+#define GIT_READ_BUFFER_SIZE (16 * 1024)
+
+typedef struct {
+ git_net_url url;
+ git_stream *stream;
+
+ git_vector auth_challenges;
+ git_http_auth_context *auth_context;
+} git_http_server;
+
+typedef enum {
+ PROXY = 1,
+ SERVER
+} git_http_server_t;
+
+typedef enum {
+ NONE = 0,
+ SENDING_REQUEST,
+ SENDING_BODY,
+ SENT_REQUEST,
+ HAS_EARLY_RESPONSE,
+ READING_RESPONSE,
+ READING_BODY,
+ DONE
+} http_client_state;
+
+/* Parser state */
+typedef enum {
+ PARSE_HEADER_NONE = 0,
+ PARSE_HEADER_NAME,
+ PARSE_HEADER_VALUE,
+ PARSE_HEADER_COMPLETE
+} parse_header_state;
+
+typedef enum {
+ PARSE_STATUS_OK,
+ PARSE_STATUS_NO_OUTPUT,
+ PARSE_STATUS_ERROR
+} parse_status;
+
+typedef struct {
+ git_http_client *client;
+ git_http_response *response;
+
+ /* Temporary buffers to avoid extra mallocs */
+ git_buf parse_header_name;
+ git_buf parse_header_value;
+
+ /* Parser state */
+ int error;
+ parse_status parse_status;
+
+ /* Headers parsing */
+ parse_header_state parse_header_state;
+
+ /* Body parsing */
+ char *output_buf; /* Caller's output buffer */
+ size_t output_size; /* Size of caller's output buffer */
+ size_t output_written; /* Bytes we've written to output buffer */
+} http_parser_context;
+
+/* HTTP client connection */
+struct git_http_client {
+ git_http_client_options opts;
+
+ /* Are we writing to the proxy or server, and state of the client. */
+ git_http_server_t current_server;
+ http_client_state state;
+
+ http_parser parser;
+
+ git_http_server server;
+ git_http_server proxy;
+
+ unsigned request_count;
+ unsigned connected : 1,
+ proxy_connected : 1,
+ keepalive : 1,
+ request_chunked : 1;
+
+ /* Temporary buffers to avoid extra mallocs */
+ git_buf request_msg;
+ git_buf read_buf;
+
+ /* A subset of information from the request */
+ size_t request_body_len,
+ request_body_remain;
+
+ /*
+ * When state == HAS_EARLY_RESPONSE, the response of our proxy
+ * that we have buffered and will deliver during read_response.
+ */
+ git_http_response early_response;
+};
+
+bool git_http_response_is_redirect(git_http_response *response)
+{
+ return (response->status == GIT_HTTP_MOVED_PERMANENTLY ||
+ response->status == GIT_HTTP_FOUND ||
+ response->status == GIT_HTTP_SEE_OTHER ||
+ response->status == GIT_HTTP_TEMPORARY_REDIRECT ||
+ response->status == GIT_HTTP_PERMANENT_REDIRECT);
+}
+
+void git_http_response_dispose(git_http_response *response)
+{
+ assert(response);
+
+ git__free(response->content_type);
+ git__free(response->location);
+
+ memset(response, 0, sizeof(git_http_response));
+}
+
+static int on_header_complete(http_parser *parser)
+{
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+ git_http_client *client = ctx->client;
+ git_http_response *response = ctx->response;
+
+ git_buf *name = &ctx->parse_header_name;
+ git_buf *value = &ctx->parse_header_value;
+
+ if (!strcasecmp("Content-Type", name->ptr)) {
+ if (response->content_type) {
+ git_error_set(GIT_ERROR_HTTP,
+ "multiple content-type headers");
+ return -1;
+ }
+
+ response->content_type =
+ git__strndup(value->ptr, value->size);
+ GIT_ERROR_CHECK_ALLOC(ctx->response->content_type);
+ } else if (!strcasecmp("Content-Length", name->ptr)) {
+ int64_t len;
+
+ if (response->content_length) {
+ git_error_set(GIT_ERROR_HTTP,
+ "multiple content-length headers");
+ return -1;
+ }
+
+ if (git__strntol64(&len, value->ptr, value->size,
+ NULL, 10) < 0 || len < 0) {
+ git_error_set(GIT_ERROR_HTTP,
+ "invalid content-length");
+ return -1;
+ }
+
+ response->content_length = (size_t)len;
+ } else if (!strcasecmp("Transfer-Encoding", name->ptr) &&
+ !strcasecmp("chunked", value->ptr)) {
+ ctx->response->chunked = 1;
+ } else if (!strcasecmp("Proxy-Authenticate", git_buf_cstr(name))) {
+ char *dup = git__strndup(value->ptr, value->size);
+ GIT_ERROR_CHECK_ALLOC(dup);
+
+ if (git_vector_insert(&client->proxy.auth_challenges, dup) < 0)
+ return -1;
+ } else if (!strcasecmp("WWW-Authenticate", name->ptr)) {
+ char *dup = git__strndup(value->ptr, value->size);
+ GIT_ERROR_CHECK_ALLOC(dup);
+
+ if (git_vector_insert(&client->server.auth_challenges, dup) < 0)
+ return -1;
+ } else if (!strcasecmp("Location", name->ptr)) {
+ if (response->location) {
+ git_error_set(GIT_ERROR_HTTP,
+ "multiple location headers");
+ return -1;
+ }
+
+ response->location = git__strndup(value->ptr, value->size);
+ GIT_ERROR_CHECK_ALLOC(response->location);
+ }
+
+ return 0;
+}
+
+static int on_header_field(http_parser *parser, const char *str, size_t len)
+{
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+
+ switch (ctx->parse_header_state) {
+ /*
+ * We last saw a header value, process the name/value pair and
+ * get ready to handle this new name.
+ */
+ case PARSE_HEADER_VALUE:
+ if (on_header_complete(parser) < 0)
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+
+ git_buf_clear(&ctx->parse_header_name);
+ git_buf_clear(&ctx->parse_header_value);
+ /* Fall through */
+
+ case PARSE_HEADER_NONE:
+ case PARSE_HEADER_NAME:
+ ctx->parse_header_state = PARSE_HEADER_NAME;
+
+ if (git_buf_put(&ctx->parse_header_name, str, len) < 0)
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+
+ break;
+
+ default:
+ git_error_set(GIT_ERROR_HTTP,
+ "header name seen at unexpected time");
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+ }
+
+ return 0;
+}
+
+static int on_header_value(http_parser *parser, const char *str, size_t len)
+{
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+
+ switch (ctx->parse_header_state) {
+ case PARSE_HEADER_NAME:
+ case PARSE_HEADER_VALUE:
+ ctx->parse_header_state = PARSE_HEADER_VALUE;
+
+ if (git_buf_put(&ctx->parse_header_value, str, len) < 0)
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+
+ break;
+
+ default:
+ git_error_set(GIT_ERROR_HTTP,
+ "header value seen at unexpected time");
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+ }
+
+ return 0;
+}
+
+GIT_INLINE(bool) challenge_matches_scheme(
+ const char *challenge,
+ git_http_auth_scheme *scheme)
+{
+ const char *scheme_name = scheme->name;
+ size_t scheme_len = strlen(scheme_name);
+
+ if (!strncasecmp(challenge, scheme_name, scheme_len) &&
+ (challenge[scheme_len] == '\0' || challenge[scheme_len] == ' '))
+ return true;
+
+ return false;
+}
+
+static git_http_auth_scheme *scheme_for_challenge(const char *challenge)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
+ if (challenge_matches_scheme(challenge, &auth_schemes[i]))
+ return &auth_schemes[i];
+ }
+
+ return NULL;
+}
+
+GIT_INLINE(void) collect_authinfo(
+ unsigned int *schemetypes,
+ unsigned int *credtypes,
+ git_vector *challenges)
+{
+ git_http_auth_scheme *scheme;
+ const char *challenge;
+ size_t i;
+
+ *schemetypes = 0;
+ *credtypes = 0;
+
+ git_vector_foreach(challenges, i, challenge) {
+ if ((scheme = scheme_for_challenge(challenge)) != NULL) {
+ *schemetypes |= scheme->type;
+ *credtypes |= scheme->credtypes;
+ }
+ }
+}
+
+static int resend_needed(git_http_client *client, git_http_response *response)
+{
+ git_http_auth_context *auth_context;
+
+ if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED &&
+ (auth_context = client->server.auth_context) &&
+ auth_context->is_complete &&
+ !auth_context->is_complete(auth_context))
+ return 1;
+
+ if (response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
+ (auth_context = client->proxy.auth_context) &&
+ auth_context->is_complete &&
+ !auth_context->is_complete(auth_context))
+ return 1;
+
+ return 0;
+}
+
+static int on_headers_complete(http_parser *parser)
+{
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+
+ /* Finalize the last seen header */
+ switch (ctx->parse_header_state) {
+ case PARSE_HEADER_VALUE:
+ if (on_header_complete(parser) < 0)
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+
+ /* Fall through */
+
+ case PARSE_HEADER_NONE:
+ ctx->parse_header_state = PARSE_HEADER_COMPLETE;
+ break;
+
+ default:
+ git_error_set(GIT_ERROR_HTTP,
+ "header completion at unexpected time");
+ return ctx->parse_status = PARSE_STATUS_ERROR;
+ }
+
+ ctx->response->status = parser->status_code;
+ ctx->client->keepalive = http_should_keep_alive(parser);
+
+ /* Prepare for authentication */
+ collect_authinfo(&ctx->response->server_auth_schemetypes,
+ &ctx->response->server_auth_credtypes,
+ &ctx->client->server.auth_challenges);
+ collect_authinfo(&ctx->response->proxy_auth_schemetypes,
+ &ctx->response->proxy_auth_credtypes,
+ &ctx->client->proxy.auth_challenges);
+
+ ctx->response->resend_credentials = resend_needed(ctx->client,
+ ctx->response);
+
+ /* Stop parsing. */
+ http_parser_pause(parser, 1);
+
+ if (ctx->response->content_type || ctx->response->chunked)
+ ctx->client->state = READING_BODY;
+ else
+ ctx->client->state = DONE;
+
+ return 0;
+}
+
+static int on_body(http_parser *parser, const char *buf, size_t len)
+{
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+ size_t max_len;
+
+ /* Saw data when we expected not to (eg, in consume_response_body) */
+ if (ctx->output_buf == NULL && ctx->output_size == 0) {
+ ctx->parse_status = PARSE_STATUS_NO_OUTPUT;
+ return 0;
+ }
+
+ assert(ctx->output_size >= ctx->output_written);
+
+ max_len = min(ctx->output_size - ctx->output_written, len);
+ max_len = min(max_len, INT_MAX);
+
+ memcpy(ctx->output_buf + ctx->output_written, buf, max_len);
+ ctx->output_written += max_len;
+
+ return 0;
+}
+
+static int on_message_complete(http_parser *parser)
+{
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+
+ ctx->client->state = DONE;
+ return 0;
+}
+
+GIT_INLINE(int) stream_write(
+ git_http_server *server,
+ const char *data,
+ size_t len)
+{
+ git_trace(GIT_TRACE_TRACE,
+ "Sending request:\n%.*s", (int)len, data);
+
+ return git_stream__write_full(server->stream, data, len, 0);
+}
+
+GIT_INLINE(int) client_write_request(git_http_client *client)
+{
+ git_stream *stream = client->current_server == PROXY ?
+ client->proxy.stream : client->server.stream;
+
+ git_trace(GIT_TRACE_TRACE,
+ "Sending request:\n%.*s",
+ (int)client->request_msg.size, client->request_msg.ptr);
+
+ return git_stream__write_full(stream,
+ client->request_msg.ptr,
+ client->request_msg.size,
+ 0);
+}
+
+static const char *name_for_method(git_http_method method)
+{
+ switch (method) {
+ case GIT_HTTP_METHOD_GET:
+ return "GET";
+ case GIT_HTTP_METHOD_POST:
+ return "POST";
+ case GIT_HTTP_METHOD_CONNECT:
+ return "CONNECT";
+ }
+
+ return NULL;
+}
+
+/*
+ * Find the scheme that is suitable for the given credentials, based on the
+ * server's auth challenges.
+ */
+static bool best_scheme_and_challenge(
+ git_http_auth_scheme **scheme_out,
+ const char **challenge_out,
+ git_vector *challenges,
+ git_credential *credentials)
+{
+ const char *challenge;
+ size_t i, j;
+
+ for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
+ git_vector_foreach(challenges, j, challenge) {
+ git_http_auth_scheme *scheme = &auth_schemes[i];
+
+ if (challenge_matches_scheme(challenge, scheme) &&
+ (scheme->credtypes & credentials->credtype)) {
+ *scheme_out = scheme;
+ *challenge_out = challenge;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Find the challenge from the server for our current auth context.
+ */
+static const char *challenge_for_context(
+ git_vector *challenges,
+ git_http_auth_context *auth_ctx)
+{
+ const char *challenge;
+ size_t i, j;
+
+ for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
+ if (auth_schemes[i].type == auth_ctx->type) {
+ git_http_auth_scheme *scheme = &auth_schemes[i];
+
+ git_vector_foreach(challenges, j, challenge) {
+ if (challenge_matches_scheme(challenge, scheme))
+ return challenge;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static const char *init_auth_context(
+ git_http_server *server,
+ git_vector *challenges,
+ git_credential *credentials)
+{
+ git_http_auth_scheme *scheme;
+ const char *challenge;
+ int error;
+
+ if (!best_scheme_and_challenge(&scheme, &challenge, challenges, credentials)) {
+ git_error_set(GIT_ERROR_HTTP, "could not find appropriate mechanism for credentials");
+ return NULL;
+ }
+
+ error = scheme->init_context(&server->auth_context, &server->url);
+
+ if (error == GIT_PASSTHROUGH) {
+ git_error_set(GIT_ERROR_HTTP, "'%s' authentication is not supported", scheme->name);
+ return NULL;
+ }
+
+ return challenge;
+}
+
+static void free_auth_context(git_http_server *server)
+{
+ if (!server->auth_context)
+ return;
+
+ if (server->auth_context->free)
+ server->auth_context->free(server->auth_context);
+
+ server->auth_context = NULL;
+}
+
+static int apply_credentials(
+ git_buf *buf,
+ git_http_server *server,
+ const char *header_name,
+ git_credential *credentials)
+{
+ git_http_auth_context *auth = server->auth_context;
+ git_vector *challenges = &server->auth_challenges;
+ const char *challenge;
+ git_buf token = GIT_BUF_INIT;
+ int error = 0;
+
+ /* We've started a new request without creds; free the context. */
+ if (auth && !credentials) {
+ free_auth_context(server);
+ return 0;
+ }
+
+ /* We haven't authenticated, nor were we asked to. Nothing to do. */
+ if (!auth && !git_vector_length(challenges))
+ return 0;
+
+ if (!auth) {
+ challenge = init_auth_context(server, challenges, credentials);
+ auth = server->auth_context;
+
+ if (!challenge || !auth) {
+ error = -1;
+ goto done;
+ }
+ } else if (auth->set_challenge) {
+ challenge = challenge_for_context(challenges, auth);
+ }
+
+ if (auth->set_challenge && challenge &&
+ (error = auth->set_challenge(auth, challenge)) < 0)
+ goto done;
+
+ if ((error = auth->next_token(&token, auth, credentials)) < 0)
+ goto done;
+
+ if (auth->is_complete && auth->is_complete(auth)) {
+ /*
+ * If we're done with an auth mechanism with connection affinity,
+ * we don't need to send any more headers and can dispose the context.
+ */
+ if (auth->connection_affinity)
+ free_auth_context(server);
+ } else if (!token.size) {
+ git_error_set(GIT_ERROR_HTTP, "failed to respond to authentication challenge");
+ error = -1;
+ goto done;
+ }
+
+ if (token.size > 0)
+ error = git_buf_printf(buf, "%s: %s\r\n", header_name, token.ptr);
+
+done:
+ git_buf_dispose(&token);
+ return error;
+}
+
+GIT_INLINE(int) apply_server_credentials(
+ git_buf *buf,
+ git_http_client *client,
+ git_http_request *request)
+{
+ return apply_credentials(buf,
+ &client->server,
+ "Authorization",
+ request->credentials);
+}
+
+GIT_INLINE(int) apply_proxy_credentials(
+ git_buf *buf,
+ git_http_client *client,
+ git_http_request *request)
+{
+ return apply_credentials(buf,
+ &client->proxy,
+ "Proxy-Authorization",
+ request->proxy_credentials);
+}
+
+static int generate_connect_request(
+ git_http_client *client,
+ git_http_request *request)
+{
+ git_buf *buf;
+ int error;
+
+ git_buf_clear(&client->request_msg);
+ buf = &client->request_msg;
+
+ git_buf_printf(buf, "CONNECT %s:%s HTTP/1.1\r\n",
+ client->server.url.host, client->server.url.port);
+
+ git_buf_puts(buf, "User-Agent: ");
+ git_http__user_agent(buf);
+ git_buf_puts(buf, "\r\n");
+
+ git_buf_printf(buf, "Host: %s\r\n", client->proxy.url.host);
+
+ if ((error = apply_proxy_credentials(buf, client, request) < 0))
+ return -1;
+
+ git_buf_puts(buf, "\r\n");
+
+ return git_buf_oom(buf) ? -1 : 0;
+}
+
+static int generate_request(
+ git_http_client *client,
+ git_http_request *request)
+{
+ git_buf *buf;
+ size_t i;
+ int error;
+
+ assert(client && request);
+
+ git_buf_clear(&client->request_msg);
+ buf = &client->request_msg;
+
+ /* GET|POST path HTTP/1.1 */
+ git_buf_puts(buf, name_for_method(request->method));
+ git_buf_putc(buf, ' ');
+
+ if (request->proxy && strcmp(request->url->scheme, "https"))
+ git_net_url_fmt(buf, request->url);
+ else
+ git_net_url_fmt_path(buf, request->url);
+
+ git_buf_puts(buf, " HTTP/1.1\r\n");
+
+ git_buf_puts(buf, "User-Agent: ");
+ git_http__user_agent(buf);
+ git_buf_puts(buf, "\r\n");
+
+ git_buf_printf(buf, "Host: %s", request->url->host);
+
+ if (!git_net_url_is_default_port(request->url))
+ git_buf_printf(buf, ":%s", request->url->port);
+
+ git_buf_puts(buf, "\r\n");
+
+ if (request->accept)
+ git_buf_printf(buf, "Accept: %s\r\n", request->accept);
+ else
+ git_buf_puts(buf, "Accept: */*\r\n");
+
+ if (request->content_type)
+ git_buf_printf(buf, "Content-Type: %s\r\n",
+ request->content_type);
+
+ if (request->chunked)
+ git_buf_puts(buf, "Transfer-Encoding: chunked\r\n");
+
+ if (request->content_length > 0)
+ git_buf_printf(buf, "Content-Length: %"PRIuZ "\r\n",
+ request->content_length);
+
+ if (request->expect_continue)
+ git_buf_printf(buf, "Expect: 100-continue\r\n");
+
+ if ((error = apply_server_credentials(buf, client, request)) < 0 ||
+ (error = apply_proxy_credentials(buf, client, request)) < 0)
+ return error;
+
+ if (request->custom_headers) {
+ for (i = 0; i < request->custom_headers->count; i++) {
+ const char *hdr = request->custom_headers->strings[i];
+
+ if (hdr)
+ git_buf_printf(buf, "%s\r\n", hdr);
+ }
+ }
+
+ git_buf_puts(buf, "\r\n");
+
+ if (git_buf_oom(buf))
+ return -1;
+
+ return 0;
+}
+
+static int check_certificate(
+ git_stream *stream,
+ git_net_url *url,
+ int is_valid,
+ git_transport_certificate_check_cb cert_cb,
+ void *cert_cb_payload)
+{
+ git_cert *cert;
+ git_error_state last_error = {0};
+ int error;
+
+ if ((error = git_stream_certificate(&cert, stream)) < 0)
+ return error;
+
+ git_error_state_capture(&last_error, GIT_ECERTIFICATE);
+
+ error = cert_cb(cert, is_valid, url->host, cert_cb_payload);
+
+ if (error == GIT_PASSTHROUGH && !is_valid)
+ return git_error_state_restore(&last_error);
+ else if (error == GIT_PASSTHROUGH)
+ error = 0;
+ else if (error && !git_error_last())
+ git_error_set(GIT_ERROR_HTTP,
+ "user rejected certificate for %s", url->host);
+
+ git_error_state_free(&last_error);
+ return error;
+}
+
+static int server_connect_stream(
+ git_http_server *server,
+ git_transport_certificate_check_cb cert_cb,
+ void *cb_payload)
+{
+ int error;
+
+ GIT_ERROR_CHECK_VERSION(server->stream, GIT_STREAM_VERSION, "git_stream");
+
+ error = git_stream_connect(server->stream);
+
+ if (error && error != GIT_ECERTIFICATE)
+ return error;
+
+ if (git_stream_is_encrypted(server->stream) && cert_cb != NULL)
+ error = check_certificate(server->stream, &server->url, !error,
+ cert_cb, cb_payload);
+
+ return error;
+}
+
+static void reset_auth_connection(git_http_server *server)
+{
+ /*
+ * If we've authenticated and we're doing "normal"
+ * authentication with a request affinity (Basic, Digest)
+ * then we want to _keep_ our context, since authentication
+ * survives even through non-keep-alive connections. If
+ * we've authenticated and we're doing connection-based
+ * authentication (NTLM, Negotiate) - indicated by the presence
+ * of an `is_complete` callback - then we need to restart
+ * authentication on a new connection.
+ */
+
+ if (server->auth_context &&
+ server->auth_context->connection_affinity)
+ free_auth_context(server);
+}
+
+/*
+ * Updates the server data structure with the new URL; returns 1 if the server
+ * has changed and we need to reconnect, returns 0 otherwise.
+ */
+GIT_INLINE(int) server_setup_from_url(
+ git_http_server *server,
+ git_net_url *url)
+{
+ if (!server->url.scheme || strcmp(server->url.scheme, url->scheme) ||
+ !server->url.host || strcmp(server->url.host, url->host) ||
+ !server->url.port || strcmp(server->url.port, url->port)) {
+ git__free(server->url.scheme);
+ git__free(server->url.host);
+ git__free(server->url.port);
+
+ server->url.scheme = git__strdup(url->scheme);
+ GIT_ERROR_CHECK_ALLOC(server->url.scheme);
+
+ server->url.host = git__strdup(url->host);
+ GIT_ERROR_CHECK_ALLOC(server->url.host);
+
+ server->url.port = git__strdup(url->port);
+ GIT_ERROR_CHECK_ALLOC(server->url.port);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void reset_parser(git_http_client *client)
+{
+ http_parser_init(&client->parser, HTTP_RESPONSE);
+}
+
+static int setup_hosts(
+ git_http_client *client,
+ git_http_request *request)
+{
+ int ret, diff = 0;
+
+ assert(client && request && request->url);
+
+ if ((ret = server_setup_from_url(&client->server, request->url)) < 0)
+ return ret;
+
+ diff |= ret;
+
+ if (request->proxy &&
+ (ret = server_setup_from_url(&client->proxy, request->proxy)) < 0)
+ return ret;
+
+ diff |= ret;
+
+ if (diff) {
+ free_auth_context(&client->server);
+ free_auth_context(&client->proxy);
+
+ client->connected = 0;
+ }
+
+ return 0;
+}
+
+GIT_INLINE(int) server_create_stream(git_http_server *server)
+{
+ git_net_url *url = &server->url;
+
+ if (strcasecmp(url->scheme, "https") == 0)
+ return git_tls_stream_new(&server->stream, url->host, url->port);
+ else if (strcasecmp(url->scheme, "http") == 0)
+ return git_socket_stream_new(&server->stream, url->host, url->port);
+
+ git_error_set(GIT_ERROR_HTTP, "unknown http scheme '%s'", url->scheme);
+ return -1;
+}
+
+GIT_INLINE(void) save_early_response(
+ git_http_client *client,
+ git_http_response *response)
+{
+ /* Buffer the response so we can return it in read_response */
+ client->state = HAS_EARLY_RESPONSE;
+
+ memcpy(&client->early_response, response, sizeof(git_http_response));
+ memset(response, 0, sizeof(git_http_response));
+}
+
+static int proxy_connect(
+ git_http_client *client,
+ git_http_request *request)
+{
+ git_http_response response = {0};
+ int error;
+
+ if (!client->proxy_connected || !client->keepalive) {
+ git_trace(GIT_TRACE_DEBUG, "Connecting to proxy %s:%s",
+ client->proxy.url.host, client->proxy.url.port);
+
+ if ((error = server_create_stream(&client->proxy)) < 0 ||
+ (error = server_connect_stream(&client->proxy,
+ client->opts.proxy_certificate_check_cb,
+ client->opts.proxy_certificate_check_payload)) < 0)
+ goto done;
+
+ client->proxy_connected = 1;
+ }
+
+ client->current_server = PROXY;
+ client->state = SENDING_REQUEST;
+
+ if ((error = generate_connect_request(client, request)) < 0 ||
+ (error = client_write_request(client)) < 0)
+ goto done;
+
+ client->state = SENT_REQUEST;
+
+ if ((error = git_http_client_read_response(&response, client)) < 0 ||
+ (error = git_http_client_skip_body(client)) < 0)
+ goto done;
+
+ assert(client->state == DONE);
+
+ if (response.status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+ save_early_response(client, &response);
+
+ error = GIT_RETRY;
+ goto done;
+ } else if (response.status != GIT_HTTP_STATUS_OK) {
+ git_error_set(GIT_ERROR_HTTP, "proxy returned unexpected status: %d", response.status);
+ error = -1;
+ goto done;
+ }
+
+ reset_parser(client);
+ client->state = NONE;
+
+done:
+ git_http_response_dispose(&response);
+ return error;
+}
+
+static int server_connect(git_http_client *client)
+{
+ git_net_url *url = &client->server.url;
+ git_transport_certificate_check_cb cert_cb;
+ void *cert_payload;
+ int error;
+
+ client->current_server = SERVER;
+
+ if (client->proxy.stream)
+ error = git_tls_stream_wrap(&client->server.stream, client->proxy.stream, url->host);
+ else
+ error = server_create_stream(&client->server);
+
+ if (error < 0)
+ goto done;
+
+ cert_cb = client->opts.server_certificate_check_cb;
+ cert_payload = client->opts.server_certificate_check_payload;
+
+ error = server_connect_stream(&client->server, cert_cb, cert_payload);
+
+done:
+ return error;
+}
+
+GIT_INLINE(void) close_stream(git_http_server *server)
+{
+ if (server->stream) {
+ git_stream_close(server->stream);
+ git_stream_free(server->stream);
+ server->stream = NULL;
+ }
+}
+
+static int http_client_connect(
+ git_http_client *client,
+ git_http_request *request)
+{
+ bool use_proxy = false;
+ int error;
+
+ if ((error = setup_hosts(client, request)) < 0)
+ goto on_error;
+
+ /* We're connected to our destination server; no need to reconnect */
+ if (client->connected && client->keepalive &&
+ (client->state == NONE || client->state == DONE))
+ return 0;
+
+ client->connected = 0;
+ client->request_count = 0;
+
+ close_stream(&client->server);
+ reset_auth_connection(&client->server);
+
+ reset_parser(client);
+
+ /* Reconnect to the proxy if necessary. */
+ use_proxy = client->proxy.url.host &&
+ !strcmp(client->server.url.scheme, "https");
+
+ if (use_proxy) {
+ if (!client->proxy_connected || !client->keepalive ||
+ (client->state != NONE && client->state != DONE)) {
+ close_stream(&client->proxy);
+ reset_auth_connection(&client->proxy);
+
+ client->proxy_connected = 0;
+ }
+
+ if ((error = proxy_connect(client, request)) < 0)
+ goto on_error;
+ }
+
+ git_trace(GIT_TRACE_DEBUG, "Connecting to remote %s:%s",
+ client->server.url.host, client->server.url.port);
+
+ if ((error = server_connect(client)) < 0)
+ goto on_error;
+
+ client->connected = 1;
+ return error;
+
+on_error:
+ if (error != GIT_RETRY)
+ close_stream(&client->proxy);
+
+ close_stream(&client->server);
+ return error;
+}
+
+GIT_INLINE(int) client_read(git_http_client *client)
+{
+ http_parser_context *parser_context = client->parser.data;
+ git_stream *stream;
+ char *buf = client->read_buf.ptr + client->read_buf.size;
+ size_t max_len;
+ ssize_t read_len;
+
+ stream = client->current_server == PROXY ?
+ client->proxy.stream : client->server.stream;
+
+ /*
+ * We use a git_buf for convenience, but statically allocate it and
+ * don't resize. Limit our consumption to INT_MAX since calling
+ * functions use an int return type to return number of bytes read.
+ */
+ max_len = client->read_buf.asize - client->read_buf.size;
+ max_len = min(max_len, INT_MAX);
+
+ if (parser_context->output_size)
+ max_len = min(max_len, parser_context->output_size);
+
+ if (max_len == 0) {
+ git_error_set(GIT_ERROR_HTTP, "no room in output buffer");
+ return -1;
+ }
+
+ read_len = git_stream_read(stream, buf, max_len);
+
+ if (read_len >= 0) {
+ client->read_buf.size += read_len;
+
+ git_trace(GIT_TRACE_TRACE, "Received:\n%.*s",
+ (int)read_len, buf);
+ }
+
+ return (int)read_len;
+}
+
+static bool parser_settings_initialized;
+static http_parser_settings parser_settings;
+
+GIT_INLINE(http_parser_settings *) http_client_parser_settings(void)
+{
+ if (!parser_settings_initialized) {
+ parser_settings.on_header_field = on_header_field;
+ parser_settings.on_header_value = on_header_value;
+ parser_settings.on_headers_complete = on_headers_complete;
+ parser_settings.on_body = on_body;
+ parser_settings.on_message_complete = on_message_complete;
+
+ parser_settings_initialized = true;
+ }
+
+ return &parser_settings;
+}
+
+GIT_INLINE(int) client_read_and_parse(git_http_client *client)
+{
+ http_parser *parser = &client->parser;
+ http_parser_context *ctx = (http_parser_context *) parser->data;
+ unsigned char http_errno;
+ int read_len;
+ size_t parsed_len;
+
+ /*
+ * If we have data in our read buffer, that means we stopped early
+ * when parsing headers. Use the data in the read buffer instead of
+ * reading more from the socket.
+ */
+ if (!client->read_buf.size && (read_len = client_read(client)) < 0)
+ return read_len;
+
+ parsed_len = http_parser_execute(parser,
+ http_client_parser_settings(),
+ client->read_buf.ptr,
+ client->read_buf.size);
+ http_errno = client->parser.http_errno;
+
+ if (parsed_len > INT_MAX) {
+ git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse");
+ return -1;
+ }
+
+ if (ctx->parse_status == PARSE_STATUS_ERROR) {
+ client->connected = 0;
+ return ctx->error ? ctx->error : -1;
+ }
+
+ /*
+ * If we finished reading the headers or body, we paused parsing.
+ * Otherwise the parser will start filling the body, or even parse
+ * a new response if the server pipelined us multiple responses.
+ * (This can happen in response to an expect/continue request,
+ * where the server gives you a 100 and 200 simultaneously.)
+ */
+ if (http_errno == HPE_PAUSED) {
+ /*
+ * http-parser has a "feature" where it will not deliver the
+ * final byte when paused in a callback. Consume that byte.
+ * https://github.com/nodejs/http-parser/issues/97
+ */
+ assert(client->read_buf.size > parsed_len);
+
+ http_parser_pause(parser, 0);
+
+ parsed_len += http_parser_execute(parser,
+ http_client_parser_settings(),
+ client->read_buf.ptr + parsed_len,
+ 1);
+ }
+
+ /* Most failures will be reported in http_errno */
+ else if (parser->http_errno != HPE_OK) {
+ git_error_set(GIT_ERROR_HTTP, "http parser error: %s",
+ http_errno_description(http_errno));
+ return -1;
+ }
+
+ /* Otherwise we should have consumed the entire buffer. */
+ else if (parsed_len != client->read_buf.size) {
+ git_error_set(GIT_ERROR_HTTP,
+ "http parser did not consume entire buffer: %s",
+ http_errno_description(http_errno));
+ return -1;
+ }
+
+ /* recv returned 0, the server hung up on us */
+ else if (!parsed_len) {
+ git_error_set(GIT_ERROR_HTTP, "unexpected EOF");
+ return -1;
+ }
+
+ git_buf_consume_bytes(&client->read_buf, parsed_len);
+
+ return (int)parsed_len;
+}
+
+/*
+ * See if we've consumed the entire response body. If the client was
+ * reading the body but did not consume it entirely, it's possible that
+ * they knew that the stream had finished (in a git response, seeing a
+ * final flush) and stopped reading. But if the response was chunked,
+ * we may have not consumed the final chunk marker. Consume it to
+ * ensure that we don't have it waiting in our socket. If there's
+ * more than just a chunk marker, close the connection.
+ */
+static void complete_response_body(git_http_client *client)
+{
+ http_parser_context parser_context = {0};
+
+ /* If we're not keeping alive, don't bother. */
+ if (!client->keepalive) {
+ client->connected = 0;
+ goto done;
+ }
+
+ parser_context.client = client;
+ client->parser.data = &parser_context;
+
+ /* If there was an error, just close the connection. */
+ if (client_read_and_parse(client) < 0 ||
+ parser_context.error != HPE_OK ||
+ (parser_context.parse_status != PARSE_STATUS_OK &&
+ parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
+ git_error_clear();
+ client->connected = 0;
+ }
+
+done:
+ git_buf_clear(&client->read_buf);
+}
+
+int git_http_client_send_request(
+ git_http_client *client,
+ git_http_request *request)
+{
+ git_http_response response = {0};
+ int error = -1;
+
+ assert(client && request);
+
+ /* If the client did not finish reading, clean up the stream. */
+ if (client->state == READING_BODY)
+ complete_response_body(client);
+
+ /* If we're waiting for proxy auth, don't sending more requests. */
+ if (client->state == HAS_EARLY_RESPONSE)
+ return 0;
+
+ if (git_trace_level() >= GIT_TRACE_DEBUG) {
+ git_buf url = GIT_BUF_INIT;
+ git_net_url_fmt(&url, request->url);
+ git_trace(GIT_TRACE_DEBUG, "Sending %s request to %s",
+ name_for_method(request->method),
+ url.ptr ? url.ptr : "<invalid>");
+ git_buf_dispose(&url);
+ }
+
+ if ((error = http_client_connect(client, request)) < 0 ||
+ (error = generate_request(client, request)) < 0 ||
+ (error = client_write_request(client)) < 0)
+ goto done;
+
+ client->state = SENT_REQUEST;
+
+ if (request->expect_continue) {
+ if ((error = git_http_client_read_response(&response, client)) < 0 ||
+ (error = git_http_client_skip_body(client)) < 0)
+ goto done;
+
+ error = 0;
+
+ if (response.status != GIT_HTTP_STATUS_CONTINUE) {
+ save_early_response(client, &response);
+ goto done;
+ }
+ }
+
+ if (request->content_length || request->chunked) {
+ client->state = SENDING_BODY;
+ client->request_body_len = request->content_length;
+ client->request_body_remain = request->content_length;
+ client->request_chunked = request->chunked;
+ }
+
+ reset_parser(client);
+
+done:
+ if (error == GIT_RETRY)
+ error = 0;
+
+ git_http_response_dispose(&response);
+ return error;
+}
+
+bool git_http_client_has_response(git_http_client *client)
+{
+ return (client->state == HAS_EARLY_RESPONSE ||
+ client->state > SENT_REQUEST);
+}
+
+int git_http_client_send_body(
+ git_http_client *client,
+ const char *buffer,
+ size_t buffer_len)
+{
+ git_http_server *server;
+ git_buf hdr = GIT_BUF_INIT;
+ int error;
+
+ assert(client);
+
+ /* If we're waiting for proxy auth, don't sending more requests. */
+ if (client->state == HAS_EARLY_RESPONSE)
+ return 0;
+
+ if (client->state != SENDING_BODY) {
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
+ return -1;
+ }
+
+ if (!buffer_len)
+ return 0;
+
+ server = &client->server;
+
+ if (client->request_body_len) {
+ assert(buffer_len <= client->request_body_remain);
+
+ if ((error = stream_write(server, buffer, buffer_len)) < 0)
+ goto done;
+
+ client->request_body_remain -= buffer_len;
+ } else {
+ if ((error = git_buf_printf(&hdr, "%" PRIxZ "\r\n", buffer_len)) < 0 ||
+ (error = stream_write(server, hdr.ptr, hdr.size)) < 0 ||
+ (error = stream_write(server, buffer, buffer_len)) < 0 ||
+ (error = stream_write(server, "\r\n", 2)) < 0)
+ goto done;
+ }
+
+done:
+ git_buf_dispose(&hdr);
+ return error;
+}
+
+static int complete_request(git_http_client *client)
+{
+ int error = 0;
+
+ assert(client && client->state == SENDING_BODY);
+
+ if (client->request_body_len && client->request_body_remain) {
+ git_error_set(GIT_ERROR_HTTP, "truncated write");
+ error = -1;
+ } else if (client->request_chunked) {
+ error = stream_write(&client->server, "0\r\n\r\n", 5);
+ }
+
+ client->state = SENT_REQUEST;
+ return error;
+}
+
+int git_http_client_read_response(
+ git_http_response *response,
+ git_http_client *client)
+{
+ http_parser_context parser_context = {0};
+ int error;
+
+ assert(response && client);
+
+ if (client->state == SENDING_BODY) {
+ if ((error = complete_request(client)) < 0)
+ goto done;
+ }
+
+ if (client->state == HAS_EARLY_RESPONSE) {
+ memcpy(response, &client->early_response, sizeof(git_http_response));
+ memset(&client->early_response, 0, sizeof(git_http_response));
+ client->state = DONE;
+ return 0;
+ }
+
+ if (client->state != SENT_REQUEST) {
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
+ error = -1;
+ goto done;
+ }
+
+ git_http_response_dispose(response);
+
+ if (client->current_server == PROXY) {
+ git_vector_free_deep(&client->proxy.auth_challenges);
+ } else if(client->current_server == SERVER) {
+ git_vector_free_deep(&client->server.auth_challenges);
+ }
+
+ client->state = READING_RESPONSE;
+ client->keepalive = 0;
+ client->parser.data = &parser_context;
+
+ parser_context.client = client;
+ parser_context.response = response;
+
+ while (client->state == READING_RESPONSE) {
+ if ((error = client_read_and_parse(client)) < 0)
+ goto done;
+ }
+
+ assert(client->state == READING_BODY || client->state == DONE);
+
+done:
+ git_buf_dispose(&parser_context.parse_header_name);
+ git_buf_dispose(&parser_context.parse_header_value);
+
+ return error;
+}
+
+int git_http_client_read_body(
+ git_http_client *client,
+ char *buffer,
+ size_t buffer_size)
+{
+ http_parser_context parser_context = {0};
+ int error = 0;
+
+ if (client->state == DONE)
+ return 0;
+
+ if (client->state != READING_BODY) {
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
+ return -1;
+ }
+
+ /*
+ * Now we'll read from the socket and http_parser will pipeline the
+ * data directly to the client.
+ */
+
+ parser_context.client = client;
+ parser_context.output_buf = buffer;
+ parser_context.output_size = buffer_size;
+
+ client->parser.data = &parser_context;
+
+ /*
+ * Clients expect to get a non-zero amount of data from us,
+ * so we either block until we have data to return, until we
+ * hit EOF or there's an error. Do this in a loop, since we
+ * may end up reading only some stream metadata (like chunk
+ * information).
+ */
+ while (!parser_context.output_written) {
+ error = client_read_and_parse(client);
+
+ if (error <= 0)
+ goto done;
+
+ if (client->state == DONE)
+ break;
+ }
+
+ assert(parser_context.output_written <= INT_MAX);
+ error = (int)parser_context.output_written;
+
+done:
+ if (error < 0)
+ client->connected = 0;
+
+ return error;
+}
+
+int git_http_client_skip_body(git_http_client *client)
+{
+ http_parser_context parser_context = {0};
+ int error;
+
+ if (client->state == DONE)
+ return 0;
+
+ if (client->state != READING_BODY) {
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
+ return -1;
+ }
+
+ parser_context.client = client;
+ client->parser.data = &parser_context;
+
+ do {
+ error = client_read_and_parse(client);
+
+ if (parser_context.error != HPE_OK ||
+ (parser_context.parse_status != PARSE_STATUS_OK &&
+ parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
+ git_error_set(GIT_ERROR_HTTP,
+ "unexpected data handled in callback");
+ error = -1;
+ }
+ } while (!error);
+
+ if (error < 0)
+ client->connected = 0;
+
+ return error;
+}
+
+/*
+ * Create an http_client capable of communicating with the given remote
+ * host.
+ */
+int git_http_client_new(
+ git_http_client **out,
+ git_http_client_options *opts)
+{
+ git_http_client *client;
+
+ assert(out);
+
+ client = git__calloc(1, sizeof(git_http_client));
+ GIT_ERROR_CHECK_ALLOC(client);
+
+ git_buf_init(&client->read_buf, GIT_READ_BUFFER_SIZE);
+ GIT_ERROR_CHECK_ALLOC(client->read_buf.ptr);
+
+ if (opts)
+ memcpy(&client->opts, opts, sizeof(git_http_client_options));
+
+ *out = client;
+ return 0;
+}
+
+GIT_INLINE(void) http_server_close(git_http_server *server)
+{
+ if (server->stream) {
+ git_stream_close(server->stream);
+ git_stream_free(server->stream);
+ server->stream = NULL;
+ }
+
+ git_net_url_dispose(&server->url);
+
+ git_vector_free_deep(&server->auth_challenges);
+ free_auth_context(server);
+}
+
+static void http_client_close(git_http_client *client)
+{
+ http_server_close(&client->server);
+ http_server_close(&client->proxy);
+
+ git_buf_dispose(&client->request_msg);
+
+ client->state = 0;
+ client->request_count = 0;
+ client->connected = 0;
+ client->keepalive = 0;
+}
+
+void git_http_client_free(git_http_client *client)
+{
+ if (!client)
+ return;
+
+ http_client_close(client);
+ git_buf_dispose(&client->read_buf);
+ git__free(client);
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_transports_httpclient_h__
+#define INCLUDE_transports_httpclient_h__
+
+#include "common.h"
+#include "net.h"
+
+#define GIT_HTTP_STATUS_CONTINUE 100
+#define GIT_HTTP_STATUS_OK 200
+#define GIT_HTTP_MOVED_PERMANENTLY 301
+#define GIT_HTTP_FOUND 302
+#define GIT_HTTP_SEE_OTHER 303
+#define GIT_HTTP_TEMPORARY_REDIRECT 307
+#define GIT_HTTP_PERMANENT_REDIRECT 308
+#define GIT_HTTP_STATUS_UNAUTHORIZED 401
+#define GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED 407
+
+typedef struct git_http_client git_http_client;
+
+/** Method for the HTTP request */
+typedef enum {
+ GIT_HTTP_METHOD_GET,
+ GIT_HTTP_METHOD_POST,
+ GIT_HTTP_METHOD_CONNECT
+} git_http_method;
+
+/** An HTTP request */
+typedef struct {
+ git_http_method method; /**< Method for the request */
+ git_net_url *url; /**< Full request URL */
+ git_net_url *proxy; /**< Proxy to use */
+
+ /* Headers */
+ const char *accept; /**< Contents of the Accept header */
+ const char *content_type; /**< Content-Type header (for POST) */
+ git_credential *credentials; /**< Credentials to authenticate with */
+ git_credential *proxy_credentials; /**< Credentials for proxy */
+ git_strarray *custom_headers; /**< Additional headers to deliver */
+
+ /* To POST a payload, either set content_length OR set chunked. */
+ size_t content_length; /**< Length of the POST body */
+ unsigned chunked : 1, /**< Post with chunking */
+ expect_continue : 1; /**< Use expect/continue negotiation */
+} git_http_request;
+
+typedef struct {
+ int status;
+
+ /* Headers */
+ char *content_type;
+ size_t content_length;
+ char *location;
+
+ /* Authentication headers */
+ unsigned server_auth_schemetypes; /**< Schemes requested by remote */
+ unsigned server_auth_credtypes; /**< Supported cred types for remote */
+
+ unsigned proxy_auth_schemetypes; /**< Schemes requested by proxy */
+ unsigned proxy_auth_credtypes; /**< Supported cred types for proxy */
+
+ unsigned chunked : 1, /**< Response body is chunked */
+ resend_credentials : 1; /**< Resend with authentication */
+} git_http_response;
+
+typedef struct {
+ /** Certificate check callback for the remote */
+ git_transport_certificate_check_cb server_certificate_check_cb;
+ void *server_certificate_check_payload;
+
+ /** Certificate check callback for the proxy */
+ git_transport_certificate_check_cb proxy_certificate_check_cb;
+ void *proxy_certificate_check_payload;
+} git_http_client_options;
+
+/**
+ * Create a new httpclient instance with the given options.
+ *
+ * @param out pointer to receive the new instance
+ * @param opts options to create the client with or NULL for defaults
+ */
+extern int git_http_client_new(
+ git_http_client **out,
+ git_http_client_options *opts);
+
+/*
+ * Sends a request to the host specified by the request URL. If the
+ * method is POST, either the the content_length or the chunked flag must
+ * be specified. The body should be provided in subsequent calls to
+ * git_http_client_send_body.
+ *
+ * @param client the client to write the request to
+ * @param request the request to send
+ */
+extern int git_http_client_send_request(
+ git_http_client *client,
+ git_http_request *request);
+
+/*
+ * After sending a request, there may already be a response to read --
+ * either because there was a non-continue response to an expect: continue
+ * request, or because the server pipelined a response to us before we even
+ * sent the request. Examine the state.
+ *
+ * @param client the client to examine
+ * @return true if there's already a response to read, false otherwise
+ */
+extern bool git_http_client_has_response(git_http_client *client);
+
+/**
+ * Sends the given buffer to the remote as part of the request body. The
+ * request must have specified either a content_length or the chunked flag.
+ *
+ * @param client the client to write the request body to
+ * @param buffer the request body
+ * @param buffer_len number of bytes of the buffer to send
+ */
+extern int git_http_client_send_body(
+ git_http_client *client,
+ const char *buffer,
+ size_t buffer_len);
+
+/**
+ * Reads the headers of a response to a request. This will consume the
+ * entirety of the headers of a response from the server. The body (if any)
+ * can be read by calling git_http_client_read_body. Callers must free
+ * the response with git_http_response_dispose.
+ *
+ * @param response pointer to the response object to fill
+ * @param client the client to read the response from
+ */
+extern int git_http_client_read_response(
+ git_http_response *response,
+ git_http_client *client);
+
+/**
+ * Reads some or all of the body of a response. At most buffer_size (or
+ * INT_MAX) bytes will be read and placed into the buffer provided. The
+ * number of bytes read will be returned, or 0 to indicate that the end of
+ * the body has been read.
+ *
+ * @param client the client to read the response from
+ * @param buffer pointer to the buffer to fill
+ * @param buffer_size the maximum number of bytes to read
+ * @return the number of bytes read, 0 on end of body, or error code
+ */
+extern int git_http_client_read_body(
+ git_http_client *client,
+ char *buffer,
+ size_t buffer_size);
+
+/**
+ * Reads all of the (remainder of the) body of the response and ignores it.
+ * None of the data from the body will be returned to the caller.
+ *
+ * @param client the client to read the response from
+ * @return 0 or an error code
+ */
+extern int git_http_client_skip_body(git_http_client *client);
+
+/**
+ * Examines the status code of the response to determine if it is a
+ * redirect of any type (eg, 301, 302, etc).
+ *
+ * @param response the response to inspect
+ * @return true if the response is a redirect, false otherwise
+ */
+extern bool git_http_response_is_redirect(git_http_response *response);
+
+/**
+ * Frees any memory associated with the response.
+ *
+ * @param response the response to free
+ */
+extern void git_http_response_dispose(git_http_response *response);
+
+/**
+ * Frees any memory associated with the client. If any sockets are open,
+ * they will be closed.
+ *
+ * @param client the client to free
+ */
+extern void git_http_client_free(git_http_client *client);
+
+#endif
}
t->have_refs = 1;
- git_strarray_free(&ref_names);
+ git_strarray_dispose(&ref_names);
return 0;
on_error:
git_vector_free(&t->refs);
- git_strarray_free(&ref_names);
+ git_strarray_dispose(&ref_names);
return -1;
}
static int local_connect(
git_transport *transport,
const char *url,
- git_cred_acquire_cb cred_acquire_cb,
+ git_credential_acquire_cb cred_acquire_cb,
void *cred_acquire_payload,
const git_proxy_options *proxy,
int direction, int flags)
if (lref[0] != '\0') {
/* Create or update a ref */
error = git_reference_create(NULL, remote_repo, rref, loid,
- !git_oid_iszero(roid), NULL);
+ !git_oid_is_zero(roid), NULL);
} else {
/* Delete a ref */
if ((error = git_reference_lookup(&remote_ref, remote_repo, rref)) < 0) {
return error;
}
-static int transfer_to_push_transfer(const git_transfer_progress *stats, void *payload)
+static int transfer_to_push_transfer(const git_indexer_progress *stats, void *payload)
{
const git_remote_callbacks *cbs = payload;
}
typedef struct foreach_data {
- git_transfer_progress *stats;
- git_transfer_progress_cb progress_cb;
+ git_indexer_progress *stats;
+ git_indexer_progress_cb progress_cb;
void *progress_payload;
git_odb_writepack *writepack;
} foreach_data;
if (git_buf_oom(&progress_info))
return -1;
- error = t->progress_cb(git_buf_cstr(&progress_info), git_buf_len(&progress_info), t->message_cb_payload);
+ error = t->progress_cb(git_buf_cstr(&progress_info), (int)git_buf_len(&progress_info), t->message_cb_payload);
git_buf_dispose(&progress_info);
return error;
static int local_download_pack(
git_transport *transport,
git_repository *repo,
- git_transfer_progress *stats,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress *stats,
+ git_indexer_progress_cb progress_cb,
void *progress_payload)
{
transport_local *t = (transport_local*)transport;
goto cleanup;
if (t->progress_cb &&
- (error = t->progress_cb(git_buf_cstr(&progress_info), git_buf_len(&progress_info), t->message_cb_payload)) < 0)
+ (error = t->progress_cb(git_buf_cstr(&progress_info), (int)git_buf_len(&progress_info), t->message_cb_payload)) < 0)
goto cleanup;
/* Walk the objects, building a packfile */
goto cleanup;
if (t->progress_cb &&
- (error = t->progress_cb(git_buf_cstr(&progress_info), git_buf_len(&progress_info), t->message_cb_payload)) < 0)
+ (error = t->progress_cb(git_buf_cstr(&progress_info), (int)git_buf_len(&progress_info), t->message_cb_payload)) < 0)
goto cleanup;
if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0)
git_transport_certificate_check_cb certificate_check_cb,
void *message_cb_payload)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
t->progress_cb = progress_cb;
t->error_cb = error_cb;
return 0;
}
-static int http_header_name_length(const char *http_header)
+static size_t http_header_name_length(const char *http_header)
{
const char *colon = strchr(http_header, ':');
if (!colon)
static bool is_malformed_http_header(const char *http_header)
{
const char *c;
- int name_len;
+ size_t name_len;
/* Disallow \r and \n */
c = strchr(http_header, '\r');
static bool is_forbidden_custom_header(const char *custom_header)
{
unsigned long i;
- int name_len = http_header_name_length(custom_header);
+ size_t name_len = http_header_name_length(custom_header);
/* Disallow headers that we set */
for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++)
git_transport *transport,
const git_strarray *custom_headers)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
size_t i;
if (t->custom_headers.count)
- git_strarray_free(&t->custom_headers);
+ git_strarray_dispose(&t->custom_headers);
if (!custom_headers)
return 0;
static int git_smart__connect(
git_transport *transport,
const char *url,
- git_cred_acquire_cb cred_acquire_cb,
+ git_credential_acquire_cb cred_acquire_cb,
void *cred_acquire_payload,
const git_proxy_options *proxy,
int direction,
int flags)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
git_smart_subtransport_stream *stream;
int error;
git_pkt *pkt;
if ((error = git_smart__detect_caps(first, &t->caps, &symrefs)) == 0) {
/* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */
if (1 == t->refs.length && !strcmp(first->head.name, "capabilities^{}") &&
- git_oid_iszero(&first->head.oid)) {
+ git_oid_is_zero(&first->head.oid)) {
git_vector_clear(&t->refs);
git_pkt_free((git_pkt *)first);
}
static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
if (!t->have_refs) {
git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs");
int git_smart__negotiation_step(git_transport *transport, void *data, size_t len)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
git_smart_subtransport_stream *stream;
int error;
static void git_smart__cancel(git_transport *transport)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
git_atomic_set(&t->cancelled, 1);
}
static int git_smart__is_connected(git_transport *transport)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
return t->connected;
}
static int git_smart__read_flags(git_transport *transport, int *flags)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
*flags = t->flags;
static int git_smart__close(git_transport *transport)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
git_vector *common = &t->common;
unsigned int i;
git_pkt *p;
static void git_smart__free(git_transport *transport)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
git_vector *refs = &t->refs;
unsigned int i;
git_pkt *p;
git_vector_free(refs);
git__free((char *)t->proxy.url);
- git_strarray_free(&t->custom_headers);
+ git_strarray_dispose(&t->custom_headers);
git__free(t);
}
int git_transport_smart_certificate_check(git_transport *transport, git_cert *cert, int valid, const char *hostname)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
assert(transport && cert && hostname);
return t->certificate_check_cb(cert, valid, hostname, t->message_cb_payload);
}
-int git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods)
+int git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods)
{
- transport_smart *t = (transport_smart *)transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
assert(out && transport);
int git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport)
{
- transport_smart *t = (transport_smart *) transport;
+ transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
return git_proxy_options_dup(out, &t->proxy);
}
git_transport parent;
git_remote *owner;
char *url;
- git_cred_acquire_cb cred_acquire_cb;
+ git_credential_acquire_cb cred_acquire_cb;
void *cred_acquire_payload;
git_proxy_options proxy;
int direction;
int git_smart__download_pack(
git_transport *transport,
git_repository *repo,
- git_transfer_progress *stats,
- git_transfer_progress_cb progress_cb,
+ git_indexer_progress *stats,
+ git_indexer_progress_cb progress_cb,
void *progress_payload);
/* smart.c */
line += 3;
len -= 3;
- if (line[len - 1] == '\n')
+ if (len && line[len - 1] == '\n')
--len;
GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
#include "pack-objects.h"
#include "remote.h"
#include "util.h"
+#include "revwalk.h"
#define NETWORK_XFER_THRESHOLD (100*1024)
/* The minimal interval between progress updates (in seconds). */
return 0;
}
-static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
-{
- git_revwalk *walk = NULL;
- git_strarray refs;
- unsigned int i;
- git_reference *ref = NULL;
- int error;
-
- if ((error = git_reference_list(&refs, repo)) < 0)
- return error;
-
- if ((error = git_revwalk_new(&walk, repo)) < 0)
- return error;
-
- git_revwalk_sorting(walk, GIT_SORT_TIME);
-
- for (i = 0; i < refs.count; ++i) {
- git_reference_free(ref);
- ref = NULL;
-
- /* No tags */
- if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
- continue;
-
- if ((error = git_reference_lookup(&ref, repo, refs.strings[i])) < 0)
- goto on_error;
-
- if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC)
- continue;
-
- if ((error = git_revwalk_push(walk, git_reference_target(ref))) < 0)
- goto on_error;
- }
-
- *out = walk;
-
-on_error:
- if (error)
- git_revwalk_free(walk);
- git_reference_free(ref);
- git_strarray_free(&refs);
- return error;
-}
-
static int wait_while_ack(gitno_buffer *buf)
{
int error;
int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count)
{
transport_smart *t = (transport_smart *)transport;
+ git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
gitno_buffer *buf = &t->buffer;
git_buf data = GIT_BUF_INIT;
git_revwalk *walk = NULL;
if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
return error;
- if ((error = fetch_setup_walk(&walk, repo)) < 0)
+ if ((error = git_revwalk_new(&walk, repo)) < 0)
+ goto on_error;
+
+ opts.insert_by_date = 1;
+ if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0)
goto on_error;
/*
} else if (pkt_type == GIT_PKT_NAK) {
continue;
} else {
- git_error_set(GIT_ERROR_NET, "Unexpected pkt type");
+ git_error_set(GIT_ERROR_NET, "unexpected pkt type");
error = -1;
goto on_error;
}
return error;
if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
- git_error_set(GIT_ERROR_NET, "Unexpected pkt type");
+ git_error_set(GIT_ERROR_NET, "unexpected pkt type");
return -1;
}
} else {
return error;
}
-static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_transfer_progress *stats)
+static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_indexer_progress *stats)
{
int recvd;
do {
if (t->cancelled.val) {
- git_error_set(GIT_ERROR_NET, "The fetch was cancelled by the user");
+ git_error_set(GIT_ERROR_NET, "the fetch was cancelled by the user");
return GIT_EUSER;
}
struct network_packetsize_payload
{
- git_transfer_progress_cb callback;
+ git_indexer_progress_cb callback;
void *payload;
- git_transfer_progress *stats;
+ git_indexer_progress *stats;
size_t last_fired_bytes;
};
int git_smart__download_pack(
git_transport *transport,
git_repository *repo,
- git_transfer_progress *stats,
- git_transfer_progress_cb transfer_progress_cb,
+ git_indexer_progress *stats,
+ git_indexer_progress_cb progress_cb,
void *progress_payload)
{
transport_smart *t = (transport_smart *)transport;
int error = 0;
struct network_packetsize_payload npp = {0};
- memset(stats, 0, sizeof(git_transfer_progress));
+ memset(stats, 0, sizeof(git_indexer_progress));
- if (transfer_progress_cb) {
- npp.callback = transfer_progress_cb;
+ if (progress_cb) {
+ npp.callback = progress_cb;
npp.payload = progress_payload;
npp.stats = stats;
t->packetsize_cb = &network_packetsize;
}
if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
- ((error = git_odb_write_pack(&writepack, odb, transfer_progress_cb, progress_payload)) != 0))
+ ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0))
goto done;
/*
} else if (pkt->type == GIT_PKT_PROGRESS) {
if (t->progress_cb) {
git_pkt_progress *p = (git_pkt_progress *) pkt;
- error = t->progress_cb(p->data, p->len, t->message_cb_payload);
+
+ if (p->len > INT_MAX) {
+ git_error_set(GIT_ERROR_NET, "oversized progress message");
+ error = GIT_ERROR;
+ goto done;
+ }
+
+ error = t->progress_cb(p->data, (int)p->len, t->message_cb_payload);
}
} else if (pkt->type == GIT_PKT_DATA) {
git_pkt_data *p = (git_pkt_data *) pkt;
} while (1);
/*
- * Trailing execution of transfer_progress_cb, if necessary...
+ * Trailing execution of progress_cb, if necessary...
* Only the callback through the npp datastructure currently
* updates the last_fired_bytes value. It is possible that
* progress has already been reported with the correct
done:
if (writepack)
writepack->free(writepack);
- if (transfer_progress_cb) {
+ if (progress_cb) {
t->packetsize_cb = NULL;
t->packetsize_payload = NULL;
}
case GIT_PKT_PROGRESS:
if (transport->progress_cb) {
git_pkt_progress *p = (git_pkt_progress *) pkt;
- error = transport->progress_cb(p->data, p->len, transport->message_cb_payload);
+
+ if (p->len > INT_MAX) {
+ git_error_set(GIT_ERROR_NET, "oversized progress message");
+ error = GIT_ERROR;
+ goto done;
+ }
+
+ error = transport->progress_cb(p->data, (int)p->len, transport->message_cb_payload);
}
break;
default:
if (data_pkt_buf.size > 0) {
/* If there was data remaining in the pack data buffer,
* then the server sent a partial pkt-line */
- git_error_set(GIT_ERROR_NET, "Incomplete pack data pkt-line");
+ git_error_set(GIT_ERROR_NET, "incomplete pack data pkt-line");
error = GIT_ERROR;
}
goto done;
/* Remove any refs which we updated to have a zero OID. */
git_vector_rforeach(refs, i, ref) {
- if (git_oid_iszero(&ref->head.oid)) {
+ if (git_oid_is_zero(&ref->head.oid)) {
git_vector_remove(refs, i);
git_pkt_free((git_pkt *)ref);
}
{
git_smart_subtransport_stream *stream;
git_packbuilder *pb;
- git_push_transfer_progress cb;
+ git_push_transfer_progress_cb cb;
void *cb_payload;
size_t last_bytes;
double last_progress_report_time;
#include "global.h"
#include "git2.h"
#include "buffer.h"
+#include "net.h"
#include "netops.h"
#include "smart.h"
-#include "cred.h"
#include "streams/socket.h"
+#include "git2/credential.h"
+#include "git2/sys/credential.h"
+
#ifdef GIT_SSH
#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport)
git_smart_subtransport parent;
transport_smart *owner;
ssh_stream *current_stream;
- git_cred *cred;
+ git_credential *cred;
char *cmd_uploadpack;
char *cmd_receivepack;
} ssh_subtransport;
size_t *bytes_read)
{
int rc;
- ssh_stream *s = (ssh_stream *)stream;
+ ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent);
*bytes_read = 0;
const char *buffer,
size_t len)
{
- ssh_stream *s = (ssh_stream *)stream;
+ ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent);
size_t off = 0;
ssize_t ret = 0;
static void ssh_stream_free(git_smart_subtransport_stream *stream)
{
- ssh_stream *s = (ssh_stream *)stream;
+ ssh_stream *s = GIT_CONTAINER_OF(stream, ssh_stream, parent);
ssh_subtransport *t;
if (!stream)
}
static int git_ssh_extract_url_parts(
- char **host,
- char **username,
+ git_net_url *urldata,
const char *url)
{
char *colon, *at;
at = strchr(url, '@');
if (at) {
start = at + 1;
- *username = git__substrdup(url, at - url);
- GIT_ERROR_CHECK_ALLOC(*username);
+ urldata->username = git__substrdup(url, at - url);
+ GIT_ERROR_CHECK_ALLOC(urldata->username);
} else {
start = url;
- *username = NULL;
+ urldata->username = NULL;
}
if (colon == NULL || (colon < start)) {
return -1;
}
- *host = git__substrdup(start, colon - start);
- GIT_ERROR_CHECK_ALLOC(*host);
+ urldata->host = git__substrdup(start, colon - start);
+ GIT_ERROR_CHECK_ALLOC(urldata->host);
return 0;
}
-static int ssh_agent_auth(LIBSSH2_SESSION *session, git_cred_ssh_key *c) {
+static int ssh_agent_auth(LIBSSH2_SESSION *session, git_credential_ssh_key *c) {
int rc = LIBSSH2_ERROR_NONE;
struct libssh2_agent_publickey *curr, *prev = NULL;
}
static int _git_ssh_authenticate_session(
- LIBSSH2_SESSION* session,
- git_cred* cred)
+ LIBSSH2_SESSION *session,
+ git_credential *cred)
{
int rc;
do {
git_error_clear();
switch (cred->credtype) {
- case GIT_CREDTYPE_USERPASS_PLAINTEXT: {
- git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
+ case GIT_CREDENTIAL_USERPASS_PLAINTEXT: {
+ git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred;
rc = libssh2_userauth_password(session, c->username, c->password);
break;
}
- case GIT_CREDTYPE_SSH_KEY: {
- git_cred_ssh_key *c = (git_cred_ssh_key *)cred;
+ case GIT_CREDENTIAL_SSH_KEY: {
+ git_credential_ssh_key *c = (git_credential_ssh_key *)cred;
if (c->privatekey)
rc = libssh2_userauth_publickey_fromfile(
break;
}
- case GIT_CREDTYPE_SSH_CUSTOM: {
- git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred;
+ case GIT_CREDENTIAL_SSH_CUSTOM: {
+ git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred;
rc = libssh2_userauth_publickey(
session, c->username, (const unsigned char *)c->publickey,
c->publickey_len, c->sign_callback, &c->payload);
break;
}
- case GIT_CREDTYPE_SSH_INTERACTIVE: {
+ case GIT_CREDENTIAL_SSH_INTERACTIVE: {
void **abstract = libssh2_session_abstract(session);
- git_cred_ssh_interactive *c = (git_cred_ssh_interactive *)cred;
+ git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred;
/* ideally, we should be able to set this by calling
* libssh2_session_init_ex() instead of libssh2_session_init().
break;
}
#ifdef GIT_SSH_MEMORY_CREDENTIALS
- case GIT_CREDTYPE_SSH_MEMORY: {
- git_cred_ssh_key *c = (git_cred_ssh_key *)cred;
+ case GIT_CREDENTIAL_SSH_MEMORY: {
+ git_credential_ssh_key *c = (git_credential_ssh_key *)cred;
assert(c->username);
assert(c->privatekey);
return 0;
}
-static int request_creds(git_cred **out, ssh_subtransport *t, const char *user, int auth_methods)
+static int request_creds(git_credential **out, ssh_subtransport *t, const char *user, int auth_methods)
{
int error, no_callback = 0;
- git_cred *cred = NULL;
+ git_credential *cred = NULL;
if (!t->owner->cred_acquire_cb) {
no_callback = 1;
{
int rc = 0;
LIBSSH2_SESSION* s;
- git_socket_stream *socket = (git_socket_stream *) io;
+ git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent);
assert(session);
return 0;
}
+#define SSH_DEFAULT_PORT "22"
+
static int _git_ssh_setup_conn(
ssh_subtransport *t,
const char *url,
const char *cmd,
git_smart_subtransport_stream **stream)
{
- char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
- const char *default_port="22";
+ git_net_url urldata = GIT_NET_URL_INIT;
int auth_methods, error = 0;
size_t i;
ssh_stream *s;
- git_cred *cred = NULL;
+ git_credential *cred = NULL;
LIBSSH2_SESSION* session=NULL;
LIBSSH2_CHANNEL* channel=NULL;
const char *p = ssh_prefixes[i];
if (!git__prefixcmp(url, p)) {
- if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0)
+ if ((error = git_net_url_parse(&urldata, url)) < 0)
goto done;
goto post_extract;
}
}
- if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0)
+ if ((error = git_ssh_extract_url_parts(&urldata, url)) < 0)
goto done;
- port = git__strdup(default_port);
- GIT_ERROR_CHECK_ALLOC(port);
+
+ if (urldata.port == NULL)
+ urldata.port = git__strdup(SSH_DEFAULT_PORT);
+
+ GIT_ERROR_CHECK_ALLOC(urldata.port);
post_extract:
- if ((error = git_socket_stream_new(&s->io, host, port)) < 0 ||
+ if ((error = git_socket_stream_new(&s->io, urldata.host, urldata.port)) < 0 ||
(error = git_stream_connect(s->io)) < 0)
goto done;
cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2;
+#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
+ key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
+ if (key != NULL) {
+ cert.type |= GIT_CERT_SSH_SHA256;
+ memcpy(&cert.hash_sha256, key, 32);
+ }
+#endif
+
key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
if (key != NULL) {
cert.type |= GIT_CERT_SSH_SHA1;
cert_ptr = &cert;
- error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, host, t->owner->message_cb_payload);
+ error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, urldata.host, t->owner->message_cb_payload);
if (error < 0 && error != GIT_PASSTHROUGH) {
if (!git_error_last())
}
/* we need the username to ask for auth methods */
- if (!user) {
- if ((error = request_creds(&cred, t, NULL, GIT_CREDTYPE_USERNAME)) < 0)
+ if (!urldata.username) {
+ if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0)
goto done;
- user = git__strdup(((git_cred_username *) cred)->username);
+ urldata.username = git__strdup(((git_credential_username *) cred)->username);
cred->free(cred);
cred = NULL;
- if (!user)
+ if (!urldata.username)
goto done;
- } else if (user && pass) {
- if ((error = git_cred_userpass_plaintext_new(&cred, user, pass)) < 0)
+ } else if (urldata.username && urldata.password) {
+ if ((error = git_credential_userpass_plaintext_new(&cred, urldata.username, urldata.password)) < 0)
goto done;
}
- if ((error = list_auth_methods(&auth_methods, session, user)) < 0)
+ if ((error = list_auth_methods(&auth_methods, session, urldata.username)) < 0)
goto done;
error = GIT_EAUTH;
cred = NULL;
}
- if ((error = request_creds(&cred, t, user, auth_methods)) < 0)
+ if ((error = request_creds(&cred, t, urldata.username, auth_methods)) < 0)
goto done;
- if (strcmp(user, git_cred__username(cred))) {
+ if (strcmp(urldata.username, git_credential_get_username(cred))) {
git_error_set(GIT_ERROR_SSH, "username does not match previous request");
error = -1;
goto done;
}
error = _git_ssh_authenticate_session(session, cred);
+
+ if (error == GIT_EAUTH) {
+ /* refresh auth methods */
+ if ((error = list_auth_methods(&auth_methods, session, urldata.username)) < 0)
+ goto done;
+ else
+ error = GIT_EAUTH;
+ }
}
if (error < 0)
if (cred)
cred->free(cred);
- git__free(host);
- git__free(port);
- git__free(path);
- git__free(user);
- git__free(pass);
+ git_net_url_dispose(&urldata);
return error;
}
const char *url,
git_smart_service_t action)
{
- ssh_subtransport *t = (ssh_subtransport *) subtransport;
+ ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent);
switch (action) {
case GIT_SERVICE_UPLOADPACK_LS:
static int _ssh_close(git_smart_subtransport *subtransport)
{
- ssh_subtransport *t = (ssh_subtransport *) subtransport;
+ ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent);
assert(!t->current_stream);
static void _ssh_free(git_smart_subtransport *subtransport)
{
- ssh_subtransport *t = (ssh_subtransport *) subtransport;
+ ssh_subtransport *t = GIT_CONTAINER_OF(subtransport, ssh_subtransport, parent);
assert(!t->current_stream);
ptr++;
if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) {
- *out |= GIT_CREDTYPE_SSH_KEY;
- *out |= GIT_CREDTYPE_SSH_CUSTOM;
+ *out |= GIT_CREDENTIAL_SSH_KEY;
+ *out |= GIT_CREDENTIAL_SSH_CUSTOM;
#ifdef GIT_SSH_MEMORY_CREDENTIALS
- *out |= GIT_CREDTYPE_SSH_MEMORY;
+ *out |= GIT_CREDENTIAL_SSH_MEMORY;
#endif
ptr += strlen(SSH_AUTH_PUBLICKEY);
continue;
}
if (!git__prefixcmp(ptr, SSH_AUTH_PASSWORD)) {
- *out |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
+ *out |= GIT_CREDENTIAL_USERPASS_PLAINTEXT;
ptr += strlen(SSH_AUTH_PASSWORD);
continue;
}
if (!git__prefixcmp(ptr, SSH_AUTH_KEYBOARD_INTERACTIVE)) {
- *out |= GIT_CREDTYPE_SSH_INTERACTIVE;
+ *out |= GIT_CREDENTIAL_SSH_INTERACTIVE;
ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE);
continue;
}
#include "repository.h"
#include "global.h"
#include "http.h"
+#include "git2/sys/credential.h"
#include <wincrypt.h>
#include <winhttp.h>
#define WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH 0
#endif
-#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS_1_1
+#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 0x00000200
#endif
-#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS_1_2
+#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 0x00000800
#endif
+#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3
+# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3 0x00002000
+#endif
+
+#ifndef HTTP_STATUS_PERMANENT_REDIRECT
+# define HTTP_STATUS_PERMANENT_REDIRECT 308
+#endif
+
+#ifndef DWORD_MAX
+# define DWORD_MAX 0xffffffff
+#endif
+
+bool git_http__expect_continue = false;
+
static const char *prefix_https = "https://";
static const char *upload_pack_service = "upload-pack";
static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
chunked : 1;
} winhttp_stream;
+typedef struct {
+ git_net_url url;
+ git_credential *cred;
+ int auth_mechanisms;
+ bool url_cred_presented;
+} winhttp_server;
+
typedef struct {
git_smart_subtransport parent;
transport_smart *owner;
- gitno_connection_data connection_data;
- gitno_connection_data proxy_connection_data;
- git_cred *cred;
- git_cred *url_cred;
- git_cred *proxy_cred;
- int auth_mechanisms;
+
+ winhttp_server server;
+ winhttp_server proxy;
+
HINTERNET session;
HINTERNET connection;
} winhttp_subtransport;
-static int _apply_userpass_credential(HINTERNET request, DWORD target, DWORD scheme, git_cred *cred)
+static int apply_userpass_credentials(HINTERNET request, DWORD target, int mechanisms, git_credential *cred)
{
- git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
- wchar_t *user, *pass;
+ git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred;
+ wchar_t *user = NULL, *pass = NULL;
int user_len = 0, pass_len = 0, error = 0;
+ DWORD native_scheme;
+
+ if (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) {
+ native_scheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
+ } else if (mechanisms & GIT_WINHTTP_AUTH_NTLM) {
+ native_scheme = WINHTTP_AUTH_SCHEME_NTLM;
+ } else if (mechanisms & GIT_WINHTTP_AUTH_DIGEST) {
+ native_scheme = WINHTTP_AUTH_SCHEME_DIGEST;
+ } else if (mechanisms & GIT_WINHTTP_AUTH_BASIC) {
+ native_scheme = WINHTTP_AUTH_SCHEME_BASIC;
+ } else {
+ git_error_set(GIT_ERROR_HTTP, "invalid authentication scheme");
+ error = -1;
+ goto done;
+ }
if ((error = user_len = git__utf8_to_16_alloc(&user, c->username)) < 0)
goto done;
if ((error = pass_len = git__utf8_to_16_alloc(&pass, c->password)) < 0)
goto done;
- if (!WinHttpSetCredentials(request, target, scheme, user, pass, NULL)) {
+ if (!WinHttpSetCredentials(request, target, native_scheme, user, pass, NULL)) {
git_error_set(GIT_ERROR_OS, "failed to set credentials");
error = -1;
}
return error;
}
-static int apply_userpass_credential_proxy(HINTERNET request, git_cred *cred, int mechanisms)
-{
- if (GIT_WINHTTP_AUTH_DIGEST & mechanisms) {
- return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_PROXY,
- WINHTTP_AUTH_SCHEME_DIGEST, cred);
- }
-
- return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_PROXY,
- WINHTTP_AUTH_SCHEME_BASIC, cred);
-}
-
-static int apply_userpass_credential(HINTERNET request, int mechanisms, git_cred *cred)
+static int apply_default_credentials(HINTERNET request, DWORD target, int mechanisms)
{
- DWORD native_scheme;
+ DWORD autologon_level = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
+ DWORD native_scheme = 0;
- if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) ||
- (mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE)) {
+ if ((mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) != 0) {
+ native_scheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
+ } else if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) != 0) {
native_scheme = WINHTTP_AUTH_SCHEME_NTLM;
- } else if (mechanisms & GIT_WINHTTP_AUTH_BASIC) {
- native_scheme = WINHTTP_AUTH_SCHEME_BASIC;
} else {
- git_error_set(GIT_ERROR_NET, "invalid authentication scheme");
+ git_error_set(GIT_ERROR_HTTP, "invalid authentication scheme");
return -1;
}
- return _apply_userpass_credential(request, WINHTTP_AUTH_TARGET_SERVER,
- native_scheme, cred);
-}
-
-static int apply_default_credentials(HINTERNET request, int mechanisms)
-{
- /* Either the caller explicitly requested that default credentials be passed,
- * or our fallback credential callback was invoked and checked that the target
- * URI was in the appropriate Internet Explorer security zone. By setting this
- * flag, we guarantee that the credentials are delivered by WinHTTP. The default
- * is "medium" which applies to the intranet and sounds like it would correspond
- * to Internet Explorer security zones, but in fact does not. */
- DWORD data = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
- DWORD native_scheme = 0;
-
- if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) != 0)
- native_scheme = WINHTTP_AUTH_SCHEME_NTLM;
-
- if ((mechanisms & GIT_WINHTTP_AUTH_NEGOTIATE) != 0)
- native_scheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
-
- if (!native_scheme) {
- git_error_set(GIT_ERROR_NET, "invalid authentication scheme");
+ /*
+ * Autologon policy must be "low" to use default creds.
+ * This is safe as the user has explicitly requested it.
+ */
+ if (!WinHttpSetOption(request, WINHTTP_OPTION_AUTOLOGON_POLICY, &autologon_level, sizeof(DWORD))) {
+ git_error_set(GIT_ERROR_OS, "could not configure logon policy");
return -1;
}
- if (!WinHttpSetOption(request, WINHTTP_OPTION_AUTOLOGON_POLICY, &data, sizeof(DWORD)))
- return -1;
-
- if (!WinHttpSetCredentials(request, WINHTTP_AUTH_TARGET_SERVER, native_scheme, NULL, NULL, NULL))
+ if (!WinHttpSetCredentials(request, target, native_scheme, NULL, NULL, NULL)) {
+ git_error_set(GIT_ERROR_OS, "could not configure credentials");
return -1;
+ }
return 0;
}
-static int fallback_cred_acquire_cb(
- git_cred **cred,
- const char *url,
- const char *username_from_url,
+static int acquire_url_cred(
+ git_credential **cred,
unsigned int allowed_types,
- void *payload)
+ const char *username,
+ const char *password)
{
- int error = 1;
+ if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT)
+ return git_credential_userpass_plaintext_new(cred, username, password);
+
+ if ((allowed_types & GIT_CREDENTIAL_DEFAULT) && *username == '\0' && *password == '\0')
+ return git_credential_default_new(cred);
- GIT_UNUSED(username_from_url);
- GIT_UNUSED(payload);
+ return 1;
+}
+
+static int acquire_fallback_cred(
+ git_credential **cred,
+ const char *url,
+ unsigned int allowed_types)
+{
+ int error = 1;
/* If the target URI supports integrated Windows authentication
* as an authentication mechanism */
- if (GIT_CREDTYPE_DEFAULT & allowed_types) {
+ if (GIT_CREDENTIAL_DEFAULT & allowed_types) {
wchar_t *wide_url;
HRESULT hCoInitResult;
(URLZONE_LOCAL_MACHINE == dwZone ||
URLZONE_INTRANET == dwZone ||
URLZONE_TRUSTED == dwZone)) {
- git_cred *existing = *cred;
+ git_credential *existing = *cred;
if (existing)
existing->free(existing);
/* Then use default Windows credentials to authenticate this request */
- error = git_cred_default_new(cred);
+ error = git_credential_default_new(cred);
}
pISM->lpVtbl->Release(pISM);
}
- if (SUCCEEDED(hCoInitResult))
- /* Only unitialize if the call to CoInitializeEx was successful. */
- CoUninitialize();
+ /* Only unitialize if the call to CoInitializeEx was successful. */
+ if (SUCCEEDED(hCoInitResult))
+ CoUninitialize();
}
git__free(wide_url);
/* If there is no override, we should fail if WinHTTP doesn't think it's fine */
if (t->owner->certificate_check_cb == NULL && !valid) {
if (!git_error_last())
- git_error_set(GIT_ERROR_NET, "unknown certificate check failure");
+ git_error_set(GIT_ERROR_HTTP, "unknown certificate check failure");
return GIT_ECERTIFICATE;
}
- if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl)
+ if (t->owner->certificate_check_cb == NULL || git__strcmp(t->server.url.scheme, "https") != 0)
return 0;
if (!WinHttpQueryOption(s->request, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert_ctx, &cert_ctx_size)) {
cert.parent.cert_type = GIT_CERT_X509;
cert.data = cert_ctx->pbCertEncoded;
cert.len = cert_ctx->cbCertEncoded;
- error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->message_cb_payload);
+ error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->server.url.host, t->owner->message_cb_payload);
CertFreeCertificateContext(cert_ctx);
if (error == GIT_PASSTHROUGH)
error = valid ? 0 : GIT_ECERTIFICATE;
if (error < 0 && !git_error_last())
- git_error_set(GIT_ERROR_NET, "user cancelled certificate check");
+ git_error_set(GIT_ERROR_HTTP, "user cancelled certificate check");
return error;
}
s->sent_request = 0;
}
-#define SCHEME_HTTP "http://"
-#define SCHEME_HTTPS "https://"
+static int apply_credentials(
+ HINTERNET request,
+ git_net_url *url,
+ int target,
+ git_credential *creds,
+ int mechanisms)
+{
+ int error = 0;
+
+ GIT_UNUSED(url);
+
+ /* If we have creds, just apply them */
+ if (creds && creds->credtype == GIT_CREDENTIAL_USERPASS_PLAINTEXT)
+ error = apply_userpass_credentials(request, target, mechanisms, creds);
+ else if (creds && creds->credtype == GIT_CREDENTIAL_DEFAULT)
+ error = apply_default_credentials(request, target, mechanisms);
+
+ return error;
+}
static int winhttp_stream_connect(winhttp_stream *s)
{
unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS;
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
+ DWORD autologon_policy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;
+
+ const char *service_url = s->service_url;
size_t i;
const git_proxy_options *proxy_opts;
+ /* If path already ends in /, remove the leading slash from service_url */
+ if ((git__suffixcmp(t->server.url.path, "/") == 0) && (git__prefixcmp(service_url, "/") == 0))
+ service_url++;
/* Prepare URL */
- git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url);
+ git_buf_printf(&buf, "%s%s", t->server.url.path, service_url);
if (git_buf_oom(&buf))
return -1;
NULL,
WINHTTP_NO_REFERER,
types,
- t->connection_data.use_ssl ? WINHTTP_FLAG_SECURE : 0);
+ git__strcmp(t->server.url.scheme, "https") == 0 ? WINHTTP_FLAG_SECURE : 0);
if (!s->request) {
git_error_set(GIT_ERROR_OS, "failed to open request");
goto on_error;
}
+ /* Never attempt default credentials; we'll provide them explicitly. */
+ if (!WinHttpSetOption(s->request, WINHTTP_OPTION_AUTOLOGON_POLICY, &autologon_policy, sizeof(DWORD)))
+ return -1;
+
if (!WinHttpSetTimeouts(s->request, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
git_error_set(GIT_ERROR_OS, "failed to set timeouts for WinHTTP");
goto on_error;
proxy_opts = &t->owner->proxy;
if (proxy_opts->type == GIT_PROXY_AUTO) {
/* Set proxy if necessary */
- if (git_remote__get_http_proxy(t->owner->owner, !!t->connection_data.use_ssl, &proxy_url) < 0)
+ if (git_remote__get_http_proxy(t->owner->owner, (strcmp(t->server.url.scheme, "https") == 0), &proxy_url) < 0)
goto on_error;
}
else if (proxy_opts->type == GIT_PROXY_SPECIFIED) {
WINHTTP_PROXY_INFO proxy_info;
wchar_t *proxy_wide;
- if (!git__prefixcmp(proxy_url, SCHEME_HTTP)) {
- t->proxy_connection_data.use_ssl = false;
- } else if (!git__prefixcmp(proxy_url, SCHEME_HTTPS)) {
- t->proxy_connection_data.use_ssl = true;
- } else {
- git_error_set(GIT_ERROR_NET, "invalid URL: '%s'", proxy_url);
- return -1;
- }
+ git_net_url_dispose(&t->proxy.url);
- gitno_connection_data_free_ptrs(&t->proxy_connection_data);
-
- if ((error = gitno_extract_url_parts(&t->proxy_connection_data.host, &t->proxy_connection_data.port, NULL,
- &t->proxy_connection_data.user, &t->proxy_connection_data.pass, proxy_url, NULL)) < 0)
+ if ((error = git_net_url_parse(&t->proxy.url, proxy_url)) < 0)
goto on_error;
- if (t->proxy_connection_data.user && t->proxy_connection_data.pass) {
- if (t->proxy_cred) {
- t->proxy_cred->free(t->proxy_cred);
- }
-
- if ((error = git_cred_userpass_plaintext_new(&t->proxy_cred, t->proxy_connection_data.user, t->proxy_connection_data.pass)) < 0)
- goto on_error;
+ if (strcmp(t->proxy.url.scheme, "http") != 0 && strcmp(t->proxy.url.scheme, "https") != 0) {
+ git_error_set(GIT_ERROR_HTTP, "invalid URL: '%s'", proxy_url);
+ error = -1;
+ goto on_error;
}
- if (t->proxy_connection_data.use_ssl)
- git_buf_PUTS(&processed_url, SCHEME_HTTPS);
- else
- git_buf_PUTS(&processed_url, SCHEME_HTTP);
+ git_buf_puts(&processed_url, t->proxy.url.scheme);
+ git_buf_PUTS(&processed_url, "://");
- git_buf_puts(&processed_url, t->proxy_connection_data.host);
- if (t->proxy_connection_data.port)
- git_buf_printf(&processed_url, ":%s", t->proxy_connection_data.port);
+ git_buf_puts(&processed_url, t->proxy.url.host);
+
+ if (!git_net_url_is_default_port(&t->proxy.url))
+ git_buf_printf(&processed_url, ":%s", t->proxy.url.port);
if (git_buf_oom(&processed_url)) {
error = -1;
git__free(proxy_wide);
- if (t->proxy_cred) {
- if (t->proxy_cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT) {
- if ((error = apply_userpass_credential_proxy(s->request, t->proxy_cred, t->auth_mechanisms)) < 0)
- goto on_error;
- }
- }
-
+ if ((error = apply_credentials(s->request, &t->proxy.url, WINHTTP_AUTH_TARGET_PROXY, t->proxy.cred, t->proxy.auth_mechanisms)) < 0)
+ goto on_error;
}
/* Disable WinHTTP redirects so we can handle them manually. Why, you ask?
&disable_redirects,
sizeof(disable_redirects))) {
git_error_set(GIT_ERROR_OS, "failed to disable redirects");
+ error = -1;
goto on_error;
}
}
/* If requested, disable certificate validation */
- if (t->connection_data.use_ssl) {
+ if (strcmp(t->server.url.scheme, "https") == 0) {
int flags;
if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0)
goto on_error;
}
- /* If we have a credential on the subtransport, apply it to the request */
- if (t->cred &&
- t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
- apply_userpass_credential(s->request, t->auth_mechanisms, t->cred) < 0)
+ if ((error = apply_credentials(s->request, &t->server.url, WINHTTP_AUTH_TARGET_SERVER, t->server.cred, t->server.auth_mechanisms)) < 0)
goto on_error;
- else if (t->cred &&
- t->cred->credtype == GIT_CREDTYPE_DEFAULT &&
- apply_default_credentials(s->request, t->auth_mechanisms) < 0)
- goto on_error;
-
- /* If no other credentials have been applied and the URL has username and
- * password, use those */
- if (!t->cred && t->connection_data.user && t->connection_data.pass) {
- if (!t->url_cred &&
- git_cred_userpass_plaintext_new(&t->url_cred, t->connection_data.user, t->connection_data.pass) < 0)
- goto on_error;
- if (apply_userpass_credential(s->request, GIT_WINHTTP_AUTH_BASIC, t->url_cred) < 0)
- goto on_error;
- }
/* We've done everything up to calling WinHttpSendRequest. */
}
static int parse_unauthorized_response(
- HINTERNET request,
int *allowed_types,
- int *allowed_mechanisms)
+ int *allowed_mechanisms,
+ HINTERNET request)
{
DWORD supported, first, target;
}
if (WINHTTP_AUTH_SCHEME_NTLM & supported) {
- *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
- *allowed_types |= GIT_CREDTYPE_DEFAULT;
+ *allowed_types |= GIT_CREDENTIAL_USERPASS_PLAINTEXT;
+ *allowed_types |= GIT_CREDENTIAL_DEFAULT;
*allowed_mechanisms |= GIT_WINHTTP_AUTH_NTLM;
}
if (WINHTTP_AUTH_SCHEME_NEGOTIATE & supported) {
- *allowed_types |= GIT_CREDTYPE_DEFAULT;
+ *allowed_types |= GIT_CREDENTIAL_DEFAULT;
*allowed_mechanisms |= GIT_WINHTTP_AUTH_NEGOTIATE;
}
if (WINHTTP_AUTH_SCHEME_BASIC & supported) {
- *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
+ *allowed_types |= GIT_CREDENTIAL_USERPASS_PLAINTEXT;
*allowed_mechanisms |= GIT_WINHTTP_AUTH_BASIC;
}
if (WINHTTP_AUTH_SCHEME_DIGEST & supported) {
- *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
+ *allowed_types |= GIT_CREDENTIAL_USERPASS_PLAINTEXT;
*allowed_mechanisms |= GIT_WINHTTP_AUTH_DIGEST;
}
{
DWORD status;
+ GIT_UNUSED(connection);
+ GIT_UNUSED(ctx);
+ GIT_UNUSED(info_len);
+
if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
return;
status = *((DWORD *)info);
if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
- git_error_set(GIT_ERROR_NET, "SSL certificate issued for different common name");
+ git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
- git_error_set(GIT_ERROR_NET, "SSL certificate has expired");
+ git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
- git_error_set(GIT_ERROR_NET, "SSL certificate signed by unknown CA");
+ git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
- git_error_set(GIT_ERROR_NET, "SSL certificate is invalid");
+ git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
- git_error_set(GIT_ERROR_NET, "certificate revocation check failed");
+ git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
- git_error_set(GIT_ERROR_NET, "SSL certificate was revoked");
+ git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
- git_error_set(GIT_ERROR_NET, "security libraries could not be loaded");
+ git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
else
- git_error_set(GIT_ERROR_NET, "unknown security error %lu", status);
+ git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
}
static int winhttp_connect(
DWORD protocols =
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
- WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
+ WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 |
+ WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3;
t->session = NULL;
t->connection = NULL;
/* Prepare port */
- if (git__strntol32(&port, t->connection_data.port,
- strlen(t->connection_data.port), NULL, 10) < 0)
+ if (git__strntol32(&port, t->server.url.port,
+ strlen(t->server.url.port), NULL, 10) < 0)
return -1;
/* Prepare host */
- if (git__utf8_to_16_alloc(&wide_host, t->connection_data.host) < 0) {
+ if (git__utf8_to_16_alloc(&wide_host, t->server.url.host) < 0) {
git_error_set(GIT_ERROR_OS, "unable to convert host to wide characters");
return -1;
}
}
/*
- * Do a best-effort attempt to enable TLS 1.2 but allow this to
- * fail; if TLS 1.2 support is not available for some reason,
+ * Do a best-effort attempt to enable TLS 1.3 and 1.2 but allow this to
+ * fail; if TLS 1.2 or 1.3 support is not available for some reason,
* ignore the failure (it will keep the default protocols).
*/
- WinHttpSetOption(t->session,
+ if (WinHttpSetOption(t->session,
WINHTTP_OPTION_SECURE_PROTOCOLS,
&protocols,
- sizeof(protocols));
+ sizeof(protocols)) == FALSE) {
+ protocols &= ~WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3;
+ WinHttpSetOption(t->session,
+ WINHTTP_OPTION_SECURE_PROTOCOLS,
+ &protocols,
+ sizeof(protocols));
+ }
if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
git_error_set(GIT_ERROR_OS, "failed to set timeouts for WinHTTP");
return error;
}
-static int do_send_request(winhttp_stream *s, size_t len, int ignore_length)
+static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
{
int attempts;
bool success;
+ if (len > DWORD_MAX) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+
for (attempts = 0; attempts < 5; attempts++) {
- if (ignore_length) {
+ if (chunked) {
success = WinHttpSendRequest(s->request,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
success = WinHttpSendRequest(s->request,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
- len, 0);
+ (DWORD)len, 0);
}
if (success || GetLastError() != (DWORD)SEC_E_BUFFER_TOO_SMALL)
return success ? 0 : -1;
}
-static int send_request(winhttp_stream *s, size_t len, int ignore_length)
+static int send_request(winhttp_stream *s, size_t len, bool chunked)
{
int request_failed = 0, cert_valid = 1, error = 0;
DWORD ignore_flags;
git_error_clear();
- if ((error = do_send_request(s, len, ignore_length)) < 0) {
+ if ((error = do_send_request(s, len, chunked)) < 0) {
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
git_error_set(GIT_ERROR_OS, "failed to send request");
return -1;
return -1;
}
- if ((error = do_send_request(s, len, ignore_length)) < 0)
+ if ((error = do_send_request(s, len, chunked)) < 0)
git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
return error;
}
+static int acquire_credentials(
+ HINTERNET request,
+ winhttp_server *server,
+ const char *url_str,
+ git_credential_acquire_cb cred_cb,
+ void *cred_cb_payload)
+{
+ int allowed_types;
+ int error = 1;
+
+ if (parse_unauthorized_response(&allowed_types, &server->auth_mechanisms, request) < 0)
+ return -1;
+
+ if (allowed_types) {
+ git_credential_free(server->cred);
+ server->cred = NULL;
+
+ /* Start with URL-specified credentials, if there were any. */
+ if (!server->url_cred_presented && server->url.username && server->url.password) {
+ error = acquire_url_cred(&server->cred, allowed_types, server->url.username, server->url.password);
+ server->url_cred_presented = 1;
+
+ if (error < 0)
+ return error;
+ }
+
+ /* Next use the user-defined callback, if there is one. */
+ if (error > 0 && cred_cb) {
+ error = cred_cb(&server->cred, url_str, server->url.username, allowed_types, cred_cb_payload);
+
+ /* Treat GIT_PASSTHROUGH as though git_credential_acquire_cb isn't set */
+ if (error == GIT_PASSTHROUGH)
+ error = 1;
+ else if (error < 0)
+ return error;
+ }
+
+ /* Finally, invoke the fallback default credential lookup. */
+ if (error > 0) {
+ error = acquire_fallback_cred(&server->cred, url_str, allowed_types);
+
+ if (error < 0)
+ return error;
+ }
+ }
+
+ /*
+ * No error occurred but we could not find appropriate credentials.
+ * This behaves like a pass-through.
+ */
+ return error;
+}
+
static int winhttp_stream_read(
git_smart_subtransport_stream *stream,
char *buffer,
replay:
/* Enforce a reasonable cap on the number of replays */
if (replay_count++ >= GIT_HTTP_REPLAY_MAX) {
- git_error_set(GIT_ERROR_NET, "too many redirects or authentication replays");
+ git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays");
return -1;
}
if (!s->sent_request) {
- if ((error = send_request(s, s->post_body_len, 0)) < 0)
+ if ((error = send_request(s, s->post_body_len, false)) < 0)
return error;
s->sent_request = 1;
}
buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE);
+ GIT_ERROR_CHECK_ALLOC(buffer);
while (len > 0) {
DWORD bytes_written;
HTTP_STATUS_REDIRECT == status_code ||
(HTTP_STATUS_REDIRECT_METHOD == status_code &&
get_verb == s->verb) ||
- HTTP_STATUS_REDIRECT_KEEP_VERB == status_code)) {
+ HTTP_STATUS_REDIRECT_KEEP_VERB == status_code ||
+ HTTP_STATUS_PERMANENT_REDIRECT == status_code)) {
/* Check for Windows 7. This workaround is only necessary on
* Windows Vista and earlier. Windows 7 is version 6.1. */
if (!git__prefixcmp_icase(location8, prefix_https)) {
/* Upgrade to secure connection; disconnect and start over */
- if (gitno_connection_data_from_url(&t->connection_data, location8, s->service_url) < 0) {
+ if (git_net_url_apply_redirect(&t->server.url, location8, s->service_url) < 0) {
git__free(location8);
return -1;
}
goto replay;
}
- /* Handle proxy authentication failures */
- if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) {
- int allowed_types;
-
- if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanisms) < 0)
- return -1;
-
- /* TODO: extract the username from the url, no payload? */
- if (t->owner->proxy.credentials) {
- int cred_error = 1;
- cred_error = t->owner->proxy.credentials(&t->proxy_cred, t->owner->proxy.url, NULL, allowed_types, t->owner->proxy.payload);
-
- if (cred_error < 0)
- return cred_error;
- }
-
- winhttp_stream_close(s);
- goto replay;
- }
-
/* Handle authentication failures */
- if (HTTP_STATUS_DENIED == status_code && get_verb == s->verb) {
- int allowed_types;
-
- if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanisms) < 0)
- return -1;
-
- if (allowed_types) {
- int cred_error = 1;
-
- git_cred_free(t->cred);
- t->cred = NULL;
- /* Start with the user-supplied credential callback, if present */
- if (t->owner->cred_acquire_cb) {
- cred_error = t->owner->cred_acquire_cb(&t->cred, t->owner->url,
- t->connection_data.user, allowed_types, t->owner->cred_acquire_payload);
-
- /* Treat GIT_PASSTHROUGH as though git_cred_acquire_cb isn't set */
- if (cred_error == GIT_PASSTHROUGH)
- cred_error = 1;
- else if (cred_error < 0)
- return cred_error;
- }
-
- /* Invoke the fallback credentials acquisition callback if necessary */
- if (cred_error > 0) {
- cred_error = fallback_cred_acquire_cb(&t->cred, t->owner->url,
- t->connection_data.user, allowed_types, NULL);
-
- if (cred_error < 0)
- return cred_error;
- }
-
- if (!cred_error) {
- assert(t->cred);
-
- winhttp_stream_close(s);
-
- /* Successfully acquired a credential */
- goto replay;
- }
+ if (status_code == HTTP_STATUS_DENIED) {
+ int error = acquire_credentials(s->request,
+ &t->server,
+ t->owner->url,
+ t->owner->cred_acquire_cb,
+ t->owner->cred_acquire_payload);
+
+ if (error < 0) {
+ return error;
+ } else if (!error) {
+ assert(t->server.cred);
+ winhttp_stream_close(s);
+ goto replay;
+ }
+ } else if (status_code == HTTP_STATUS_PROXY_AUTH_REQ) {
+ int error = acquire_credentials(s->request,
+ &t->proxy,
+ t->owner->proxy.url,
+ t->owner->proxy.credentials,
+ t->owner->proxy.payload);
+
+ if (error < 0) {
+ return error;
+ } else if (!error) {
+ assert(t->proxy.cred);
+ winhttp_stream_close(s);
+ goto replay;
}
}
if (HTTP_STATUS_OK != status_code) {
- git_error_set(GIT_ERROR_NET, "request failed with status code: %lu", status_code);
+ git_error_set(GIT_ERROR_HTTP, "request failed with status code: %lu", status_code);
return -1;
}
}
if (wcscmp(expected_content_type, content_type)) {
- git_error_set(GIT_ERROR_NET, "received unexpected content-type");
+ git_error_set(GIT_ERROR_HTTP, "received unexpected content-type");
return -1;
}
/* This implementation of write permits only a single call. */
if (s->sent_request) {
- git_error_set(GIT_ERROR_NET, "subtransport configured for only one write");
+ git_error_set(GIT_ERROR_HTTP, "subtransport configured for only one write");
return -1;
}
- if ((error = send_request(s, len, 0)) < 0)
+ if ((error = send_request(s, len, false)) < 0)
return error;
s->sent_request = 1;
if (RPC_S_OK != status &&
RPC_S_UUID_LOCAL_ONLY != status &&
RPC_S_UUID_NO_ADDRESS != status) {
- git_error_set(GIT_ERROR_NET, "unable to generate name for temp file");
+ git_error_set(GIT_ERROR_HTTP, "unable to generate name for temp file");
return -1;
}
if (buffer_len_cch < UUID_LENGTH_CCH + 1) {
- git_error_set(GIT_ERROR_NET, "buffer too small for name of temp file");
+ git_error_set(GIT_ERROR_HTTP, "buffer too small for name of temp file");
return -1;
}
return -1;
}
- if ((error = send_request(s, 0, 1)) < 0)
+ if ((error = send_request(s, 0, true)) < 0)
return error;
s->sent_request = 1;
/* Append as much to the buffer as we can */
int count = (int)min(CACHED_POST_BODY_BUF_SIZE - s->chunk_buffer_len, len);
- if (!s->chunk_buffer)
+ if (!s->chunk_buffer) {
s->chunk_buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE);
+ GIT_ERROR_CHECK_ALLOC(s->chunk_buffer);
+ }
memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count);
s->chunk_buffer_len += count;
int ret = -1;
if (!t->connection)
- if ((ret = gitno_connection_data_from_url(&t->connection_data, url, NULL)) < 0 ||
+ if ((ret = git_net_url_parse(&t->server.url, url)) < 0 ||
(ret = winhttp_connect(t)) < 0)
return ret;
{
winhttp_subtransport *t = (winhttp_subtransport *)subtransport;
- gitno_connection_data_free_ptrs(&t->connection_data);
- memset(&t->connection_data, 0x0, sizeof(gitno_connection_data));
- gitno_connection_data_free_ptrs(&t->proxy_connection_data);
- memset(&t->proxy_connection_data, 0x0, sizeof(gitno_connection_data));
-
- if (t->cred) {
- t->cred->free(t->cred);
- t->cred = NULL;
- }
+ git_net_url_dispose(&t->server.url);
+ git_net_url_dispose(&t->proxy.url);
- if (t->proxy_cred) {
- t->proxy_cred->free(t->proxy_cred);
- t->proxy_cred = NULL;
+ if (t->server.cred) {
+ t->server.cred->free(t->server.cred);
+ t->server.cred = NULL;
}
- if (t->url_cred) {
- t->url_cred->free(t->url_cred);
- t->url_cred = NULL;
+ if (t->proxy.cred) {
+ t->proxy.cred->free(t->proxy.cred);
+ t->proxy.cred = NULL;
}
return winhttp_close_connection(t);
/* Parse children: */
if (tree->children_count > 0) {
- unsigned int i;
+ size_t i, bufsize;
- tree->children = git_pool_malloc(pool, tree->children_count * sizeof(git_tree_cache *));
+ GIT_ERROR_CHECK_ALLOC_MULTIPLY(&bufsize, tree->children_count, sizeof(git_tree_cache*));
+
+ tree->children = git_pool_malloc(pool, bufsize);
GIT_ERROR_CHECK_ALLOC(tree->children);
- memset(tree->children, 0x0, tree->children_count * sizeof(git_tree_cache *));
+ memset(tree->children, 0x0, bufsize);
for (i = 0; i < tree->children_count; ++i) {
if (read_tree_internal(&tree->children[i], &buffer, buffer_end, pool) < 0)
static int read_tree_recursive(git_tree_cache *cache, const git_tree *tree, git_pool *pool)
{
git_repository *repo;
- size_t i, j, nentries, ntrees;
+ size_t i, j, nentries, ntrees, alloc_size;
int error;
repo = git_tree_owner(tree);
ntrees++;
}
+ GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_size, ntrees, sizeof(git_tree_cache *));
+
cache->children_count = ntrees;
- cache->children = git_pool_mallocz(pool, ntrees * sizeof(git_tree_cache *));
+ cache->children = git_pool_mallocz(pool, alloc_size);
GIT_ERROR_CHECK_ALLOC(cache->children);
j = 0;
int git_tree_cache_new(git_tree_cache **out, const char *name, git_pool *pool)
{
- size_t name_len;
+ size_t name_len, alloc_size;
git_tree_cache *tree;
name_len = strlen(name);
- tree = git_pool_malloc(pool, sizeof(git_tree_cache) + name_len + 1);
+
+ GIT_ERROR_CHECK_ALLOC_ADD3(&alloc_size, sizeof(git_tree_cache), name_len, 1);
+
+ tree = git_pool_malloc(pool, alloc_size);
GIT_ERROR_CHECK_ALLOC(tree);
memset(tree, 0x0, sizeof(git_tree_cache));
#include "commit.h"
#include "git2/repository.h"
#include "git2/object.h"
-#include "fileops.h"
+#include "futils.h"
#include "tree-cache.h"
#include "index.h"
return tree->entries.size;
}
-unsigned int git_treebuilder_entrycount(git_treebuilder *bld)
+size_t git_treebuilder_entrycount(git_treebuilder *bld)
{
assert(bld);
- return git_strmap_num_entries(bld->map);
+ return git_strmap_size(bld->map);
}
static int tree_error(const char *str, const char *path)
if (!valid_entry_name(repo, filename))
return tree_error("failed to insert entry: invalid name for a tree entry", filename);
- if (git_oid_iszero(id))
+ if (git_oid_is_zero(id))
return tree_error("failed to insert entry: invalid null OID", filename);
if (filemode != GIT_FILEMODE_COMMIT &&
entry->attr = (uint16_t)filemode;
- git_strmap_insert(bld->map, entry->filename, entry, &error);
- if (error < 0) {
+ if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) {
git_tree_entry_free(entry);
git_error_set(GIT_ERROR_TREE, "failed to append entry %s to the tree builder", filename);
return -1;
bld->repo = repo;
- if (git_strmap_alloc(&bld->map) < 0) {
+ if (git_strmap_new(&bld->map) < 0) {
git__free(bld);
return -1;
}
{
git_tree_entry *entry;
int error;
- size_t pos;
assert(bld && id && filename);
if ((error = check_entry(bld->repo, filename, id, filemode)) < 0)
return error;
- pos = git_strmap_lookup_index(bld->map, filename);
- if (git_strmap_valid_index(bld->map, pos)) {
- entry = git_strmap_value_at(bld->map, pos);
+ if ((entry = git_strmap_get(bld->map, filename)) != NULL) {
git_oid_cpy((git_oid *) entry->oid, id);
} else {
entry = alloc_entry(filename, strlen(filename), id);
GIT_ERROR_CHECK_ALLOC(entry);
- git_strmap_insert(bld->map, entry->filename, entry, &error);
-
- if (error < 0) {
+ if ((error = git_strmap_set(bld->map, entry->filename, entry)) < 0) {
git_tree_entry_free(entry);
git_error_set(GIT_ERROR_TREE, "failed to insert %s", filename);
return -1;
static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename)
{
- git_tree_entry *entry = NULL;
- size_t pos;
-
assert(bld && filename);
-
- pos = git_strmap_lookup_index(bld->map, filename);
- if (git_strmap_valid_index(bld->map, pos))
- entry = git_strmap_value_at(bld->map, pos);
-
- return entry;
+ return git_strmap_get(bld->map, filename);
}
const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename)
git_buf_clear(tree);
- entrycount = git_strmap_num_entries(bld->map);
+ entrycount = git_strmap_size(bld->map);
if ((error = git_vector_init(&entries, entrycount, entry_sort_cmp)) < 0)
goto out;
return error;
}
-void git_treebuilder_filter(
+int git_treebuilder_filter(
git_treebuilder *bld,
git_treebuilder_filter_cb filter,
void *payload)
git_tree_entry_free(entry);
}
});
+
+ return 0;
}
-void git_treebuilder_clear(git_treebuilder *bld)
+int git_treebuilder_clear(git_treebuilder *bld)
{
git_tree_entry *e;
git_strmap_foreach_value(bld->map, e, git_tree_entry_free(e));
git_strmap_clear(bld->map);
+
+ return 0;
}
void git_treebuilder_free(git_treebuilder *bld)
return git__page_size(alignment);
}
-int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
+int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
{
int mprot = PROT_READ;
int mflag = 0;
# define st_atime_nsec st_atim.tv_nsec
# define st_mtime_nsec st_mtim.tv_nsec
# define st_ctime_nsec st_ctim.tv_nsec
-#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NEC)
+#elif !defined(GIT_USE_STAT_MTIME_NSEC) && defined(GIT_USE_NSEC)
# error GIT_USE_NSEC defined but unknown struct stat nanosecond type
#endif
#define p_strcasecmp(s1, s2) strcasecmp(s1, s2)
#define p_strncasecmp(s1, s2, c) strncasecmp(s1, s2, c)
#define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a)
-#define p_snprintf(b, c, ...) snprintf(b, c, __VA_ARGS__)
+#define p_snprintf snprintf
#define p_mkstemp(p) mkstemp(p)
#define p_chdir(p) chdir(p)
-#define p_chmod(p,m) chmod(p, m)
#define p_rmdir(p) rmdir(p)
#define p_access(p,m) access(p,m)
#define p_ftruncate(fd, sz) ftruncate(fd, sz)
+/*
+ * Pre-Android 5 did not implement a virtual filesystem atop FAT
+ * partitions for Unix permissions, which causes chmod to fail. However,
+ * Unix permissions have no effect on Android anyway as file permissions
+ * are not actually managed this way, so treating it as a no-op across
+ * all Android is safe.
+ */
+#ifdef __ANDROID__
+# define p_chmod(p,m) 0
+#else
+# define p_chmod(p,m) chmod(p, m)
+#endif
+
/* see win32/posix.h for explanation about why this exists */
#define p_lstat_posixly(p,b) lstat(p,b)
# define p_futimes futimes
#endif
-#ifdef GIT_USE_REGCOMP_L
-#include <xlocale.h>
-GIT_INLINE(int) p_regcomp(regex_t *preg, const char *pattern, int cflags)
-{
- return regcomp_l(preg, pattern, cflags, (locale_t) 0);
-}
-#else
-# define p_regcomp regcomp
-#endif
-
#endif
#ifndef INCLUDE_userdiff_h__
#define INCLUDE_userdiff_h__
+#include "regexp.h"
+
/*
* This file isolates the built in diff driver function name patterns.
* Most of these patterns are taken from Git (with permission from the
#define PATTERNS(NAME, FN_PATS, WORD_PAT) \
{ NAME, FN_PATS, WORD_PAT WORD_DEFAULT, 0 }
#define IPATTERN(NAME, FN_PATS, WORD_PAT) \
- { NAME, FN_PATS, WORD_PAT WORD_DEFAULT, REG_ICASE }
+ { NAME, FN_PATS, WORD_PAT WORD_DEFAULT, GIT_REGEXP_ICASE }
/*
* The table of diff driver patterns
# include <Shlwapi.h>
#endif
-void git_strarray_free(git_strarray *array)
-{
- size_t i;
-
- if (array == NULL)
- return;
-
- for (i = 0; i < array->count; ++i)
- git__free(array->strings[i]);
-
- git__free(array->strings);
-
- memset(array, 0, sizeof(*array));
-}
-
-int git_strarray_copy(git_strarray *tgt, const git_strarray *src)
-{
- size_t i;
-
- assert(tgt && src);
-
- memset(tgt, 0, sizeof(*tgt));
-
- if (!src->count)
- return 0;
-
- tgt->strings = git__calloc(src->count, sizeof(char *));
- GIT_ERROR_CHECK_ALLOC(tgt->strings);
-
- for (i = 0; i < src->count; ++i) {
- if (!src->strings[i])
- continue;
-
- tgt->strings[tgt->count] = git__strdup(src->strings[i]);
- if (!tgt->strings[tgt->count]) {
- git_strarray_free(tgt);
- memset(tgt, 0, sizeof(*tgt));
- return -1;
- }
-
- tgt->count++;
- }
-
- return 0;
-}
-
int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
{
const char *p;
tmp_int = tmp_long & 0xFFFFFFFF;
if (tmp_int != tmp_long) {
- int len = tmp_endptr - nptr;
+ int len = (int)(tmp_endptr - nptr);
git_error_set(GIT_ERROR_INVALID, "failed to convert: '%.*s' is too large", len, nptr);
return -1;
}
return error;
}
-int git__strcmp(const char *a, const char *b)
-{
- while (*a && *b && *a == *b)
- ++a, ++b;
- return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b);
-}
-
int git__strcasecmp(const char *a, const char *b)
{
while (*a && *b && git__tolower(*a) == git__tolower(*b))
return cmp;
}
-int git__strncmp(const char *a, const char *b, size_t sz)
-{
- while (sz && *a && *b && *a == *b)
- --sz, ++a, ++b;
- if (!sz)
- return 0;
- return (int)(*(const unsigned char *)a) - (int)(*(const unsigned char *)b);
-}
-
int git__strncasecmp(const char *a, const char *b, size_t sz)
{
int al, bl;
int git__prefixcmp(const char *str, const char *prefix)
{
- return prefixcmp(str, SIZE_MAX, prefix, false);
+ unsigned char s, p;
+
+ while (1) {
+ p = *prefix++;
+ s = *str++;
+
+ if (!p)
+ return 0;
+
+ if (s != p)
+ return s - p;
+ }
}
int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
last_line = (len % LINE_WIDTH);
for (i = 0; i < line_count; ++i) {
+ printf("%08" PRIxZ " ", (i * LINE_WIDTH));
+
line = buffer + (i * LINE_WIDTH);
- for (j = 0; j < LINE_WIDTH; ++j, ++line)
- printf("%02X ", (unsigned char)*line & 0xFF);
+ for (j = 0; j < LINE_WIDTH; ++j, ++line) {
+ printf("%02x ", (unsigned char)*line & 0xFF);
+
+ if (j == (LINE_WIDTH / 2))
+ printf(" ");
+ }
- printf("| ");
+ printf(" |");
line = buffer + (i * LINE_WIDTH);
for (j = 0; j < LINE_WIDTH; ++j, ++line)
printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
- printf("\n");
+ printf("|\n");
}
if (last_line > 0) {
+ printf("%08" PRIxZ " ", (line_count * LINE_WIDTH));
line = buffer + (line_count * LINE_WIDTH);
- for (j = 0; j < last_line; ++j, ++line)
- printf("%02X ", (unsigned char)*line & 0xFF);
+ for (j = 0; j < last_line; ++j, ++line) {
+ printf("%02x ", (unsigned char)*line & 0xFF);
+ if (j == (LINE_WIDTH / 2))
+ printf(" ");
+ }
+
+ if (j < (LINE_WIDTH / 2))
+ printf(" ");
for (j = 0; j < (LINE_WIDTH - last_line); ++j)
- printf(" ");
+ printf(" ");
- printf("| ");
+ printf(" |");
line = buffer + (line_count * LINE_WIDTH);
for (j = 0; j < last_line; ++j, ++line)
printf("%c", (*line >= 32 && *line <= 126) ? *line : '.');
- printf("\n");
+ printf("|\n");
}
printf("\n");
}
#endif
+
+#if !defined(HAVE_QSORT_R_BSD) && \
+ !defined(HAVE_QSORT_R_GNU) && \
+ !defined(HAVE_QSORT_S)
+static void swap(uint8_t *a, uint8_t *b, size_t elsize)
+{
+ char tmp[256];
+
+ while (elsize) {
+ size_t n = elsize < sizeof(tmp) ? elsize : sizeof(tmp);
+ memcpy(tmp, a + elsize - n, n);
+ memcpy(a + elsize - n, b + elsize - n, n);
+ memcpy(b + elsize - n, tmp, n);
+ elsize -= n;
+ }
+}
+
+static void insertsort(
+ void *els, size_t nel, size_t elsize,
+ git__sort_r_cmp cmp, void *payload)
+{
+ uint8_t *base = els;
+ uint8_t *end = base + nel * elsize;
+ uint8_t *i, *j;
+
+ for (i = base + elsize; i < end; i += elsize)
+ for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize)
+ swap(j, j - elsize, elsize);
+}
+#endif
+
void git__qsort_r(
void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload)
{
git__qsort_r_glue glue = { cmp, payload };
qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
#else
- git__insertsort_r(els, nel, elsize, NULL, cmp, payload);
+ insertsort(els, nel, elsize, cmp, payload);
#endif
}
-void git__insertsort_r(
- void *els, size_t nel, size_t elsize, void *swapel,
- git__sort_r_cmp cmp, void *payload)
-{
- uint8_t *base = els;
- uint8_t *end = base + nel * elsize;
- uint8_t *i, *j;
- bool freeswap = !swapel;
-
- if (freeswap)
- swapel = git__malloc(elsize);
-
- for (i = base + elsize; i < end; i += elsize)
- for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize) {
- memcpy(swapel, j, elsize);
- memcpy(j, j - elsize, elsize);
- memcpy(j - elsize, swapel, elsize);
- }
-
- if (freeswap)
- git__free(swapel);
-}
-
/*
* git__utf8_iterate is taken from the utf8proc project,
* http://www.public-software-group.org/utf8proc
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0
};
-int git__utf8_charlen(const uint8_t *str, int str_len)
+static int util_utf8_charlen(const uint8_t *str, size_t str_len)
{
- int length, i;
+ size_t length, i;
length = utf8proc_utf8class[str[0]];
if (!length)
return -1;
- if (str_len >= 0 && length > str_len)
- return -str_len;
+ if (str_len > 0 && length > str_len)
+ return -1;
for (i = 1; i < length; i++) {
if ((str[i] & 0xC0) != 0x80)
- return -i;
+ return -1;
}
- return length;
+ return (int)length;
}
int git__utf8_iterate(const uint8_t *str, int str_len, int32_t *dst)
int32_t uc = -1;
*dst = -1;
- length = git__utf8_charlen(str, str_len);
+ length = util_utf8_charlen(str, str_len);
if (length < 0)
return -1;
return length;
}
-double git_time_monotonic(void)
-{
- return git__timer();
-}
-
size_t git__utf8_valid_buf_length(const uint8_t *str, size_t str_len)
{
size_t offset = 0;
while (offset < str_len) {
- int length = git__utf8_charlen(str + offset, str_len - offset);
+ int length = util_utf8_charlen(str + offset, str_len - offset);
if (length < 0)
break;
# define max(a,b) ((a) > (b) ? (a) : (b))
#endif
+#if defined(__GNUC__)
+# define GIT_CONTAINER_OF(ptr, type, member) \
+ __builtin_choose_expr( \
+ __builtin_offsetof(type, member) == 0 && \
+ __builtin_types_compatible_p(typeof(&((type *) 0)->member), typeof(ptr)), \
+ ((type *) (ptr)), \
+ (void)0)
+#else
+# define GIT_CONTAINER_OF(ptr, type, member) (type *)(ptr)
+#endif
+
#define GIT_DATE_RFC2822_SZ 32
/**
extern void git__qsort_r(
void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload);
-extern void git__insertsort_r(
- void *els, size_t nel, size_t elsize, void *swapel,
- git__sort_r_cmp cmp, void *payload);
-
/**
* @param position If non-NULL, this will be set to the position where the
* element is or would be inserted if not found.
void *payload,
size_t *position);
+#define git__strcmp strcmp
+#define git__strncmp strncmp
+
extern int git__strcmp_cb(const void *a, const void *b);
extern int git__strcasecmp_cb(const void *a, const void *b);
-extern int git__strcmp(const char *a, const char *b);
extern int git__strcasecmp(const char *a, const char *b);
-extern int git__strncmp(const char *a, const char *b, size_t sz);
extern int git__strncasecmp(const char *a, const char *b, size_t sz);
extern int git__strcasesort_cmp(const char *a, const char *b);
}
#define GIT_REFCOUNT_OWN(r, o) { \
- (r)->rc.owner = o; \
+ (void)git__swap((r)->rc.owner, o); \
}
-#define GIT_REFCOUNT_OWNER(r) ((r)->rc.owner)
+#define GIT_REFCOUNT_OWNER(r) git__load((r)->rc.owner)
#define GIT_REFCOUNT_VAL(r) git_atomic_get((r)->rc.refcount)
GIT_INLINE(double) git__timer(void)
{
- /* We need the initial tick count to detect if the tick
- * count has rolled over. */
- static DWORD initial_tick_count = 0;
-
- /* GetTickCount returns the number of milliseconds that have
+ /* GetTickCount64 returns the number of milliseconds that have
* elapsed since the system was started. */
- DWORD count = GetTickCount();
-
- if(initial_tick_count == 0) {
- initial_tick_count = count;
- } else if (count < initial_tick_count) {
- /* The tick count has rolled over - adjust for it. */
- count = (0xFFFFFFFF - initial_tick_count) + count;
- }
-
- return (double) count / (double) 1000;
+ return (double) GetTickCount64() / (double) 1000;
}
#elif __APPLE__
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ *
+ * Do shell-style pattern matching for ?, \, [], and * characters.
+ * It is 8bit clean.
+ *
+ * Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+ * Rich $alz is now <rsalz@bbn.com>.
+ *
+ * Modified by Wayne Davison to special-case '/' matching, to make '**'
+ * work differently than '*', and to fix the character-class code.
+ *
+ * Imported from git.git.
+ */
+
+#include "wildmatch.h"
+
+#define GIT_SPACE 0x01
+#define GIT_DIGIT 0x02
+#define GIT_ALPHA 0x04
+#define GIT_GLOB_SPECIAL 0x08
+#define GIT_REGEX_SPECIAL 0x10
+#define GIT_PATHSPEC_MAGIC 0x20
+#define GIT_CNTRL 0x40
+#define GIT_PUNCT 0x80
+
+enum {
+ S = GIT_SPACE,
+ A = GIT_ALPHA,
+ D = GIT_DIGIT,
+ G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
+ R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | */
+ P = GIT_PATHSPEC_MAGIC, /* other non-alnum, except for ] and } */
+ X = GIT_CNTRL,
+ U = GIT_PUNCT,
+ Z = GIT_CNTRL | GIT_SPACE
+};
+
+static const unsigned char sane_ctype[256] = {
+ X, X, X, X, X, X, X, X, X, Z, Z, X, X, Z, X, X, /* 0.. 15 */
+ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 16.. 31 */
+ S, P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */
+ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */
+ P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
+ A, A, A, A, A, A, A, A, A, A, A, G, G, U, R, P, /* 80.. 95 */
+ P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
+ A, A, A, A, A, A, A, A, A, A, A, R, R, U, P, X, /* 112..127 */
+ /* Nothing in the 128.. range */
+};
+
+#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
+#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
+
+typedef unsigned char uchar;
+
+/* What character marks an inverted character class? */
+#define NEGATE_CLASS '!'
+#define NEGATE_CLASS2 '^'
+
+#define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
+ && *(class) == *(litmatch) \
+ && strncmp((char*)class, litmatch, len) == 0)
+
+#if defined STDC_HEADERS || !defined isascii
+# define ISASCII(c) 1
+#else
+# define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (ISASCII(c) && isblank(c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+#ifdef isgraph
+# define ISGRAPH(c) (ISASCII(c) && isgraph(c))
+#else
+# define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c))
+#endif
+
+#define ISPRINT(c) (ISASCII(c) && isprint(c))
+#define ISDIGIT(c) (ISASCII(c) && isdigit(c))
+#define ISALNUM(c) (ISASCII(c) && isalnum(c))
+#define ISALPHA(c) (ISASCII(c) && isalpha(c))
+#define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
+#define ISLOWER(c) (ISASCII(c) && islower(c))
+#define ISPUNCT(c) (ISASCII(c) && ispunct(c))
+#define ISSPACE(c) (ISASCII(c) && isspace(c))
+#define ISUPPER(c) (ISASCII(c) && isupper(c))
+#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
+
+/* Match pattern "p" against "text" */
+static int dowild(const uchar *p, const uchar *text, unsigned int flags)
+{
+ uchar p_ch;
+ const uchar *pattern = p;
+
+ for ( ; (p_ch = *p) != '\0'; text++, p++) {
+ int matched, match_slash, negated;
+ uchar t_ch, prev_ch;
+ if ((t_ch = *text) == '\0' && p_ch != '*')
+ return WM_ABORT_ALL;
+ if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
+ t_ch = tolower(t_ch);
+ if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
+ p_ch = tolower(p_ch);
+ switch (p_ch) {
+ case '\\':
+ /* Literal match with following character. Note that the test
+ * in "default" handles the p[1] == '\0' failure case. */
+ p_ch = *++p;
+ /* FALLTHROUGH */
+ default:
+ if (t_ch != p_ch)
+ return WM_NOMATCH;
+ continue;
+ case '?':
+ /* Match anything but '/'. */
+ if ((flags & WM_PATHNAME) && t_ch == '/')
+ return WM_NOMATCH;
+ continue;
+ case '*':
+ if (*++p == '*') {
+ const uchar *prev_p = p - 2;
+ while (*++p == '*') {}
+ if (!(flags & WM_PATHNAME))
+ /* without WM_PATHNAME, '*' == '**' */
+ match_slash = 1;
+ else if ((prev_p < pattern || *prev_p == '/') &&
+ (*p == '\0' || *p == '/' ||
+ (p[0] == '\\' && p[1] == '/'))) {
+ /*
+ * Assuming we already match 'foo/' and are at
+ * <star star slash>, just assume it matches
+ * nothing and go ahead match the rest of the
+ * pattern with the remaining string. This
+ * helps make foo/<*><*>/bar (<> because
+ * otherwise it breaks C comment syntax) match
+ * both foo/bar and foo/a/bar.
+ */
+ if (p[0] == '/' &&
+ dowild(p + 1, text, flags) == WM_MATCH)
+ return WM_MATCH;
+ match_slash = 1;
+ } else /* WM_PATHNAME is set */
+ match_slash = 0;
+ } else
+ /* without WM_PATHNAME, '*' == '**' */
+ match_slash = flags & WM_PATHNAME ? 0 : 1;
+ if (*p == '\0') {
+ /* Trailing "**" matches everything. Trailing "*" matches
+ * only if there are no more slash characters. */
+ if (!match_slash) {
+ if (strchr((char*)text, '/') != NULL)
+ return WM_NOMATCH;
+ }
+ return WM_MATCH;
+ } else if (!match_slash && *p == '/') {
+ /*
+ * _one_ asterisk followed by a slash
+ * with WM_PATHNAME matches the next
+ * directory
+ */
+ const char *slash = strchr((char*)text, '/');
+ if (!slash)
+ return WM_NOMATCH;
+ text = (const uchar*)slash;
+ /* the slash is consumed by the top-level for loop */
+ break;
+ }
+ while (1) {
+ if (t_ch == '\0')
+ break;
+ /*
+ * Try to advance faster when an asterisk is
+ * followed by a literal. We know in this case
+ * that the string before the literal
+ * must belong to "*".
+ * If match_slash is false, do not look past
+ * the first slash as it cannot belong to '*'.
+ */
+ if (!is_glob_special(*p)) {
+ p_ch = *p;
+ if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
+ p_ch = tolower(p_ch);
+ while ((t_ch = *text) != '\0' &&
+ (match_slash || t_ch != '/')) {
+ if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
+ t_ch = tolower(t_ch);
+ if (t_ch == p_ch)
+ break;
+ text++;
+ }
+ if (t_ch != p_ch)
+ return WM_NOMATCH;
+ }
+ if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
+ if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
+ return matched;
+ } else if (!match_slash && t_ch == '/')
+ return WM_ABORT_TO_STARSTAR;
+ t_ch = *++text;
+ }
+ return WM_ABORT_ALL;
+ case '[':
+ p_ch = *++p;
+#ifdef NEGATE_CLASS2
+ if (p_ch == NEGATE_CLASS2)
+ p_ch = NEGATE_CLASS;
+#endif
+ /* Assign literal 1/0 because of "matched" comparison. */
+ negated = p_ch == NEGATE_CLASS ? 1 : 0;
+ if (negated) {
+ /* Inverted character class. */
+ p_ch = *++p;
+ }
+ prev_ch = 0;
+ matched = 0;
+ do {
+ if (!p_ch)
+ return WM_ABORT_ALL;
+ if (p_ch == '\\') {
+ p_ch = *++p;
+ if (!p_ch)
+ return WM_ABORT_ALL;
+ if (t_ch == p_ch)
+ matched = 1;
+ } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
+ p_ch = *++p;
+ if (p_ch == '\\') {
+ p_ch = *++p;
+ if (!p_ch)
+ return WM_ABORT_ALL;
+ }
+ if (t_ch <= p_ch && t_ch >= prev_ch)
+ matched = 1;
+ else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch)) {
+ uchar t_ch_upper = toupper(t_ch);
+ if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch)
+ matched = 1;
+ }
+ p_ch = 0; /* This makes "prev_ch" get set to 0. */
+ } else if (p_ch == '[' && p[1] == ':') {
+ const uchar *s;
+ int i;
+ for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
+ if (!p_ch)
+ return WM_ABORT_ALL;
+ i = (int)(p - s - 1);
+ if (i < 0 || p[-1] != ':') {
+ /* Didn't find ":]", so treat like a normal set. */
+ p = s - 2;
+ p_ch = '[';
+ if (t_ch == p_ch)
+ matched = 1;
+ continue;
+ }
+ if (CC_EQ(s,i, "alnum")) {
+ if (ISALNUM(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "alpha")) {
+ if (ISALPHA(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "blank")) {
+ if (ISBLANK(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "cntrl")) {
+ if (ISCNTRL(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "digit")) {
+ if (ISDIGIT(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "graph")) {
+ if (ISGRAPH(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "lower")) {
+ if (ISLOWER(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "print")) {
+ if (ISPRINT(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "punct")) {
+ if (ISPUNCT(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "space")) {
+ if (ISSPACE(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "upper")) {
+ if (ISUPPER(t_ch))
+ matched = 1;
+ else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch))
+ matched = 1;
+ } else if (CC_EQ(s,i, "xdigit")) {
+ if (ISXDIGIT(t_ch))
+ matched = 1;
+ } else /* malformed [:class:] string */
+ return WM_ABORT_ALL;
+ p_ch = 0; /* This makes "prev_ch" get set to 0. */
+ } else if (t_ch == p_ch)
+ matched = 1;
+ } while (prev_ch = p_ch, (p_ch = *++p) != ']');
+ if (matched == negated ||
+ ((flags & WM_PATHNAME) && t_ch == '/'))
+ return WM_NOMATCH;
+ continue;
+ }
+ }
+
+ return *text ? WM_NOMATCH : WM_MATCH;
+}
+
+/* Match the "pattern" against the "text" string. */
+int wildmatch(const char *pattern, const char *text, unsigned int flags)
+{
+ return dowild((const uchar*)pattern, (const uchar*)text, flags);
+}
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_wildmatch_h__
+#define INCLUDE_wildmatch_h__
+
+#include "common.h"
+
+#define WM_CASEFOLD 1
+#define WM_PATHNAME 2
+
+#define WM_NOMATCH 1
+#define WM_MATCH 0
+#define WM_ABORT_ALL -1
+#define WM_ABORT_TO_STARSTAR -2
+
+int wildmatch(const char *pattern, const char *text, unsigned int flags);
+
+#endif
#include "../../include/git2/version.h"
#ifndef LIBGIT2_FILENAME
-# define LIBGIT2_FILENAME "git2"
+# ifdef __GNUC__
+# define LIBGIT2_FILENAME git2
+# else
+# define LIBGIT2_FILENAME "git2"
+# endif
#endif
#ifndef LIBGIT2_COMMENTS
# define LIBGIT2_COMMENTS "For more information visit http://libgit2.github.com/"
#endif
+#ifdef __GNUC__
+# define _STR(x) #x
+# define STR(x) _STR(x)
+#else
+# define STR(x) x
+#endif
+
+#ifdef __GNUC__
+VS_VERSION_INFO VERSIONINFO
+#else
VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
+#endif
FILEVERSION LIBGIT2_VER_MAJOR,LIBGIT2_VER_MINOR,LIBGIT2_VER_REVISION,LIBGIT2_VER_PATCH
PRODUCTVERSION LIBGIT2_VER_MAJOR,LIBGIT2_VER_MINOR,LIBGIT2_VER_REVISION,LIBGIT2_VER_PATCH
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
BEGIN
VALUE "FileDescription", "libgit2 - the Git linkable library\0"
VALUE "FileVersion", LIBGIT2_VERSION "\0"
- VALUE "InternalName", LIBGIT2_FILENAME ".dll\0"
+ VALUE "InternalName", STR(LIBGIT2_FILENAME) ".dll\0"
VALUE "LegalCopyright", "Copyright (C) the libgit2 contributors. All rights reserved.\0"
- VALUE "OriginalFilename", LIBGIT2_FILENAME ".dll\0"
+ VALUE "OriginalFilename", STR(LIBGIT2_FILENAME) ".dll\0"
VALUE "ProductName", "libgit2\0"
VALUE "ProductVersion", LIBGIT2_VERSION "\0"
VALUE "Comments", LIBGIT2_COMMENTS "\0"
return 0;
}
-int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
+int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
DWORD alignment = get_allocation_granularity();
DWORD view_prot = 0;
DWORD off_low = 0;
DWORD off_hi = 0;
- git_off_t page_start;
- git_off_t page_offset;
+ off64_t page_start;
+ off64_t page_offset;
GIT_MMAP_VALIDATE(out, len, prot, flags);
return -1;
}
- assert(sizeof(git_off_t) == 8);
-
off_low = (DWORD)(page_start);
off_hi = (DWORD)(page_start >> 32);
out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);
#define path__is_unc(p) \
(((p)[0] == '\\' && (p)[1] == '\\') || ((p)[0] == '/' && (p)[1] == '/'))
+#define path__startswith_slash(p) \
+ ((p)[0] == '\\' || (p)[0] == '/')
+
GIT_INLINE(int) path__cwd(wchar_t *path, int size)
{
int len;
*to = L'\0';
- return (to - path);
+ if ((to - path) > INT_MAX) {
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ return -1;
+ }
+
+ return (int)(to - path);
}
-int git_win32_path__cwd(wchar_t *out, size_t len)
+static int win32_path_cwd(wchar_t *out, size_t len)
{
int cwd_len;
- if ((cwd_len = path__cwd(out, len)) < 0)
+ if (len > INT_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ if ((cwd_len = path__cwd(out, (int)len)) < 0)
return -1;
/* UNC paths */
goto on_error;
}
/* Absolute paths omitting the drive letter */
- else if (src[0] == '\\' || src[0] == '/') {
+ else if (path__startswith_slash(src)) {
if (path__cwd(dest, MAX_PATH) < 0)
goto on_error;
else {
int cwd_len;
- if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0)
+ if ((cwd_len = win32_path_cwd(dest, MAX_PATH)) < 0)
goto on_error;
dest[cwd_len++] = L'\\';
return -1;
}
+int git_win32_path_relative_from_utf8(git_win32_path out, const char *src)
+{
+ wchar_t *dest = out, *p;
+ int len;
+
+ /* Handle absolute paths */
+ if (git_path_is_absolute(src) ||
+ path__is_nt_namespace(src) ||
+ path__is_unc(src) ||
+ path__startswith_slash(src)) {
+ return git_win32_path_from_utf8(out, src);
+ }
+
+ if ((len = git__utf8_to_16(dest, MAX_PATH, src)) < 0)
+ return -1;
+
+ for (p = dest; p < (dest + len); p++) {
+ if (*p == L'/')
+ *p = L'\\';
+ }
+
+ return len;
+}
+
int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
{
char *out = dest;
#define INCLUDE_win32_path_w32_h__
#include "common.h"
-
#include "vector.h"
-/*
- * Provides a large enough buffer to support Windows paths: MAX_PATH is
- * 260, corresponding to a maximum path length of 259 characters plus a
- * NULL terminator. Prefixing with "\\?\" adds 4 characters, but if the
- * original was a UNC path, then we turn "\\server\share" into
- * "\\?\UNC\server\share". So we replace the first two characters with
- * 8 characters, a net gain of 6, so the maximum length is MAX_PATH+6.
- */
-#define GIT_WIN_PATH_UTF16 MAX_PATH+6
-
-/* Maximum size of a UTF-8 Win32 path. We remove the "\\?\" or "\\?\UNC\"
- * prefixes for presentation, bringing us back to 259 (non-NULL)
- * characters. UTF-8 does have 4-byte sequences, but they are encoded in
- * UTF-16 using surrogate pairs, which takes up the space of two characters.
- * Two characters in the range U+0800 -> U+FFFF take up more space in UTF-8
- * (6 bytes) than one surrogate pair (4 bytes).
- */
-#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
-
-/*
- * The length of a Windows "shortname", for 8.3 compatibility.
+/**
+ * Create a Win32 path (in UCS-2 format) from a UTF-8 string. If the given
+ * path is relative, then it will be turned into an absolute path by having
+ * the current working directory prepended.
+ *
+ * @param dest The buffer to receive the wide string.
+ * @param src The UTF-8 string to convert.
+ * @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
-#define GIT_WIN_PATH_SHORTNAME 13
-
-/* Win32 path types */
-typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
-typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
+extern int git_win32_path_from_utf8(git_win32_path dest, const char *src);
/**
- * Create a Win32 path (in UCS-2 format) from a UTF-8 string.
+ * Create a Win32 path (in UCS-2 format) from a UTF-8 string. If the given
+ * path is relative, then it will not be turned into an absolute path.
*
* @param dest The buffer to receive the wide string.
* @param src The UTF-8 string to convert.
* @return The length of the wide string, in characters (not counting the NULL terminator), or < 0 for failure
*/
-extern int git_win32_path_from_utf8(git_win32_path dest, const char *src);
+extern int git_win32_path_relative_from_utf8(git_win32_path dest, const char *src);
/**
* Canonicalize a Win32 UCS-2 path so that it is suitable for delivery to the
* canonical (always backslashes, never forward slashes) and process any
* directory entries of '.' or '..'.
*
+ * Note that this is intended to be used on absolute Windows paths, those
+ * that start with `C:\`, `\\server\share`, `\\?\`, etc.
+ *
* This processes the buffer in place.
*
* @param path The buffer to process
extern int p_chmod(const char* path, mode_t mode);
extern int p_rmdir(const char* path);
extern int p_access(const char* path, mode_t mode);
-extern int p_ftruncate(int fd, git_off_t size);
+extern int p_ftruncate(int fd, off64_t size);
/* p_lstat is almost but not quite POSIX correct. Specifically, the use of
* ENOTDIR is wrong, in that it does not mean precisely that a non-directory
extern struct tm * p_localtime_r(const time_t *timer, struct tm *result);
extern struct tm * p_gmtime_r(const time_t *timer, struct tm *result);
-/* Use the bundled regcomp */
-#define p_regcomp regcomp
-
#endif
#include "common.h"
#include "../posix.h"
-#include "../fileops.h"
+#include "../futils.h"
#include "path.h"
#include "path_w32.h"
#include "utf-conv.h"
* We now take a "git_off_t" rather than "long" because
* files may be longer than 2Gb.
*/
-int p_ftruncate(int fd, git_off_t size)
+int p_ftruncate(int fd, off64_t size)
{
if (size < 0) {
errno = EINVAL;
GIT_INLINE(int) unlink_once(const wchar_t *path)
{
+ DWORD error;
+
if (DeleteFileW(path))
return 0;
+ if ((error = GetLastError()) == ERROR_ACCESS_DENIED) {
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+ if (!GetFileAttributesExW(path, GetFileExInfoStandard, &fdata) ||
+ !(fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ||
+ !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ goto out;
+
+ if (RemoveDirectoryW(path))
+ return 0;
+ }
+
+out:
+ SetLastError(error);
+
if (last_error_retryable())
return GIT_RETRY;
return (int)bufsiz;
}
+static bool target_is_dir(const char *target, const char *path)
+{
+ git_buf resolved = GIT_BUF_INIT;
+ git_win32_path resolved_w;
+ bool isdir = true;
+
+ if (git_path_is_absolute(target))
+ git_win32_path_from_utf8(resolved_w, target);
+ else if (git_path_dirname_r(&resolved, path) < 0 ||
+ git_path_apply_relative(&resolved, target) < 0 ||
+ git_win32_path_from_utf8(resolved_w, resolved.ptr) < 0)
+ goto out;
+
+ isdir = GetFileAttributesW(resolved_w) & FILE_ATTRIBUTE_DIRECTORY;
+
+out:
+ git_buf_dispose(&resolved);
+ return isdir;
+}
+
int p_symlink(const char *target, const char *path)
{
git_win32_path target_w, path_w;
DWORD dwFlags;
+ /*
+ * Convert both target and path to Windows-style paths. Note that we do
+ * not want to use `git_win32_path_from_utf8` for converting the target,
+ * as that function will automatically pre-pend the current working
+ * directory in case the path is not absolute. As Git will instead use
+ * relative symlinks, this is not someting we want.
+ */
if (git_win32_path_from_utf8(path_w, path) < 0 ||
- git__utf8_to_16(target_w, MAX_PATH, target) < 0)
+ git_win32_path_relative_from_utf8(target_w, target) < 0)
return -1;
dwFlags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
-
- if (GetFileAttributesW(target_w) & FILE_ATTRIBUTE_DIRECTORY)
+ if (target_is_dir(target, path))
dwFlags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
if (!CreateSymbolicLinkW(path_w, target_w, dwFlags))
#include <sys/types.h>
#include <sys/stat.h>
-#include <regex.h>
-
#include <io.h>
#include <direct.h>
#ifdef GIT_THREADS
thread->result = thread->proc(thread->param);
- git__free_tls_data();
-
return CLEAN_THREAD_EXIT;
}
HMODULE hModule = GetModuleHandleW(L"kernel32");
if (hModule) {
- win32_srwlock_initialize = (win32_srwlock_fn)
+ win32_srwlock_initialize = (win32_srwlock_fn)(void *)
GetProcAddress(hModule, "InitializeSRWLock");
- win32_srwlock_acquire_shared = (win32_srwlock_fn)
+ win32_srwlock_acquire_shared = (win32_srwlock_fn)(void *)
GetProcAddress(hModule, "AcquireSRWLockShared");
- win32_srwlock_release_shared = (win32_srwlock_fn)
+ win32_srwlock_release_shared = (win32_srwlock_fn)(void *)
GetProcAddress(hModule, "ReleaseSRWLockShared");
- win32_srwlock_acquire_exclusive = (win32_srwlock_fn)
+ win32_srwlock_acquire_exclusive = (win32_srwlock_fn)(void *)
GetProcAddress(hModule, "AcquireSRWLockExclusive");
- win32_srwlock_release_exclusive = (win32_srwlock_fn)
+ win32_srwlock_release_exclusive = (win32_srwlock_fn)(void *)
GetProcAddress(hModule, "ReleaseSRWLockExclusive");
}
{
assert(GIT_GLOBAL->current_thread);
GIT_GLOBAL->current_thread->result = value;
-
- git__free_tls_data();
-
ExitThread(CLEAN_THREAD_EXIT);
}
int utf8_len, utf8_write_len;
size_t new_size;
- if (!len_w)
+ if (!len_w) {
return 0;
+ } else if (len_w > INT_MAX) {
+ git_error_set_oom();
+ return -1;
+ }
assert(string_w);
/* Measure the string necessary for conversion */
- if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string_w, len_w, NULL, 0, NULL, NULL)) == 0)
+ if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string_w, (int)len_w, NULL, 0, NULL, NULL)) == 0)
return 0;
assert(utf8_len > 0);
return -1;
if ((utf8_write_len = WideCharToMultiByte(
- CP_UTF8, WC_ERR_INVALID_CHARS, string_w, len_w, &buf->ptr[buf->size], utf8_len, NULL, NULL)) == 0)
+ CP_UTF8, WC_ERR_INVALID_CHARS, string_w, (int)len_w, &buf->ptr[buf->size], utf8_len, NULL, NULL)) == 0)
return handle_wc_error();
assert(utf8_write_len == utf8_len);
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#ifndef INCLUDE_win32_w32_common_h__
+#define INCLUDE_win32_w32_common_h__
+
+/*
+ * Provides a large enough buffer to support Windows paths: MAX_PATH is
+ * 260, corresponding to a maximum path length of 259 characters plus a
+ * NULL terminator. Prefixing with "\\?\" adds 4 characters, but if the
+ * original was a UNC path, then we turn "\\server\share" into
+ * "\\?\UNC\server\share". So we replace the first two characters with
+ * 8 characters, a net gain of 6, so the maximum length is MAX_PATH+6.
+ */
+#define GIT_WIN_PATH_UTF16 MAX_PATH+6
+
+/* Maximum size of a UTF-8 Win32 path. We remove the "\\?\" or "\\?\UNC\"
+ * prefixes for presentation, bringing us back to 259 (non-NULL)
+ * characters. UTF-8 does have 4-byte sequences, but they are encoded in
+ * UTF-16 using surrogate pairs, which takes up the space of two characters.
+ * Two characters in the range U+0800 -> U+FFFF take up more space in UTF-8
+ * (6 bytes) than one surrogate pair (4 bytes).
+ */
+#define GIT_WIN_PATH_UTF8 (259 * 3 + 1)
+
+/*
+ * The length of a Windows "shortname", for 8.3 compatibility.
+ */
+#define GIT_WIN_PATH_SHORTNAME 13
+
+/* Win32 path types */
+typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16];
+typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8];
+
+#endif
static unsigned int g_checkpoint_id = 0; /* to better label leak checkpoints */
static bool g_transient_leaks_since_mark = false; /* payload for hook */
-static void *crtdbg__malloc(size_t len, const char *file, int line)
-{
- void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!ptr) git_error_set_oom();
- return ptr;
-}
-
-static void *crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line)
-{
- void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!ptr) git_error_set_oom();
- return ptr;
-}
-
-static char *crtdbg__strdup(const char *str, const char *file, int line)
-{
- char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!ptr) git_error_set_oom();
- return ptr;
-}
-
-static char *crtdbg__strndup(const char *str, size_t n, const char *file, int line)
-{
- size_t length = 0, alloclength;
- char *ptr;
-
- length = p_strnlen(str, n);
-
- if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
- !(ptr = crtdbg__malloc(alloclength, file, line)))
- return NULL;
-
- if (length)
- memcpy(ptr, str, length);
-
- ptr[length] = '\0';
-
- return ptr;
-}
-
-static char *crtdbg__substrdup(const char *start, size_t n, const char *file, int line)
-{
- char *ptr;
- size_t alloclen;
-
- if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
- !(ptr = crtdbg__malloc(alloclen, file, line)))
- return NULL;
-
- memcpy(ptr, start, n);
- ptr[n] = '\0';
- return ptr;
-}
-
-static void *crtdbg__realloc(void *ptr, size_t size, const char *file, int line)
-{
- void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
- if (!new_ptr) git_error_set_oom();
- return new_ptr;
-}
-
-static void *crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
-{
- size_t newsize;
-
- return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
- NULL : _realloc_dbg(ptr, newsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
-}
-
-static void *crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
-{
- return crtdbg__reallocarray(NULL, nelem, elsize, file, line);
-}
-
-static void crtdbg__free(void *ptr)
-{
- free(ptr);
-}
-
-int git_win32_crtdbg_init_allocator(git_allocator *allocator)
-{
- allocator->gmalloc = crtdbg__malloc;
- allocator->gcalloc = crtdbg__calloc;
- allocator->gstrdup = crtdbg__strdup;
- allocator->gstrndup = crtdbg__strndup;
- allocator->gsubstrdup = crtdbg__substrdup;
- allocator->grealloc = crtdbg__realloc;
- allocator->greallocarray = crtdbg__reallocarray;
- allocator->gmallocarray = crtdbg__mallocarray;
- allocator->gfree = crtdbg__free;
- return 0;
-}
-
/**
* Compare function for bsearch on g_cs_index table.
*/
* startup. See tests/main.c for an example.
*/
-int git_win32_crtdbg_init_allocator(git_allocator *allocator);
-
/**
* Initialize our memory leak tracking and de-dup data structures.
* This should ONLY be called by git_libgit2_init().
#include "win32/posix.h"
#include "hash.h"
-/**
- * This is supposedly defined in WinBase.h (from Windows.h) but there were linker issues.
- */
-USHORT WINAPI RtlCaptureStackBackTrace(ULONG, ULONG, PVOID*, PULONG);
-
static bool g_win32_stack_initialized = false;
static HANDLE g_win32_stack_process = INVALID_HANDLE_VALUE;
static git_win32__stack__aux_cb_alloc g_aux_cb_alloc = NULL;
}
int git_win32__stack_format(
- char *pbuf, int buf_len,
+ char *pbuf, size_t buf_len,
const git_win32__stack__raw_data *pdata,
const char *prefix, const char *suffix)
{
} s;
IMAGEHLP_LINE64 line;
- int buf_used = 0;
+ size_t buf_used = 0;
unsigned int k;
char detail[MY_MAX_FILENAME * 2]; /* filename plus space for function name and formatting */
- int detail_len;
+ size_t detail_len;
if (!g_win32_stack_initialized) {
git_error_set(GIT_ERROR_INVALID, "git_win32_stack not initialized.");
}
int git_win32__stack(
- char * pbuf, int buf_len,
+ char * pbuf, size_t buf_len,
int skip,
const char *prefix, const char *suffix)
{
* @param aux_msg A buffer where a formatted message should be written.
* @param aux_msg_len The size of the buffer.
*/
-typedef void (*git_win32__stack__aux_cb_lookup)(unsigned int aux_id, char *aux_msg, unsigned int aux_msg_len);
+typedef void (*git_win32__stack__aux_cb_lookup)(unsigned int aux_id, char *aux_msg, size_t aux_msg_len);
/**
* Register an "aux" data provider to augment our C stacktrace data.
* @param suffix String written after each frame; defaults to "\n".
*/
int git_win32__stack_format(
- char *pbuf, int buf_len,
+ char *pbuf, size_t buf_len,
const git_win32__stack__raw_data *pdata,
const char *prefix, const char *suffix);
* @param suffix String written after each frame; defaults to "\n".
*/
int git_win32__stack(
- char * pbuf, int buf_len,
+ char * pbuf, size_t buf_len,
int skip,
const char *prefix, const char *suffix);
*out = (attrs & FILE_ATTRIBUTE_HIDDEN) ? true : false;
return 0;
}
+
+int git_win32__file_attribute_to_stat(
+ struct stat *st,
+ const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
+ const wchar_t *path)
+{
+ git_win32__stat_init(st,
+ attrdata->dwFileAttributes,
+ attrdata->nFileSizeHigh,
+ attrdata->nFileSizeLow,
+ attrdata->ftCreationTime,
+ attrdata->ftLastAccessTime,
+ attrdata->ftLastWriteTime);
+
+ if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) {
+ git_win32_path target;
+
+ if (git_win32_path_readlink_w(target, path) >= 0) {
+ st->st_mode = (st->st_mode & ~S_IFMT) | S_IFLNK;
+
+ /* st_size gets the UTF-8 length of the target name, in bytes,
+ * not counting the NULL terminator */
+ if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
+ git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
*/
extern int git_win32__hidden(bool *hidden, const char *path);
+extern int git_win32__file_attribute_to_stat(
+ struct stat *st,
+ const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
+ const wchar_t *path);
+
/**
* Converts a FILETIME structure to a struct timespec.
*
st->st_uid = 0;
st->st_nlink = 1;
st->st_mode = mode;
- st->st_size = ((git_off_t)nFileSizeHigh << 32) + nFileSizeLow;
+ st->st_size = ((int64_t)nFileSizeHigh << 32) + nFileSizeLow;
st->st_dev = _getdrive() - 1;
st->st_rdev = st->st_dev;
git_win32__filetime_to_timespec(&ftLastAccessTime, &(st->st_atim));
fileinfo->ftLastWriteTime);
}
-GIT_INLINE(int) git_win32__file_attribute_to_stat(
- struct stat *st,
- const WIN32_FILE_ATTRIBUTE_DATA *attrdata,
- const wchar_t *path)
-{
- git_win32__stat_init(st,
- attrdata->dwFileAttributes,
- attrdata->nFileSizeHigh,
- attrdata->nFileSizeLow,
- attrdata->ftCreationTime,
- attrdata->ftLastAccessTime,
- attrdata->ftLastWriteTime);
-
- if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) {
- git_win32_path target;
-
- if (git_win32_path_readlink_w(target, path) >= 0) {
- st->st_mode = (st->st_mode & ~S_IFMT) | S_IFLNK;
-
- /* st_size gets the UTF-8 length of the target name, in bytes,
- * not counting the NULL terminator */
- if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) {
- git_error_set(GIT_ERROR_OS, "could not convert reparse point name for '%ls'", path);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
#endif
git_vector worktrees = GIT_VECTOR_INIT;
git_buf path = GIT_BUF_INIT;
char *worktree;
- unsigned i, len;
+ size_t i, len;
int error;
assert(wts && repo);
goto out;
}
- if ((wt->name = git__strdup(name)) == NULL
- || (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL
- || (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL
- || (parent && (wt->parent_path = git__strdup(parent)) == NULL)
- || (wt->worktree_path = git_path_dirname(wt->gitlink_path)) == NULL) {
+ if ((wt->name = git__strdup(name)) == NULL ||
+ (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL ||
+ (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL ||
+ (parent && (wt->parent_path = git__strdup(parent)) == NULL) ||
+ (wt->worktree_path = git_path_dirname(wt->gitlink_path)) == NULL) {
error = -1;
goto out;
}
goto out;
wt->gitdir_path = git_buf_detach(&gitdir);
- wt->locked = !!git_worktree_is_locked(NULL, wt);
+ if ((error = git_worktree_is_locked(NULL, wt)) < 0)
+ goto out;
+ wt->locked = !!error;
+ error = 0;
*out = wt;
if (!is_worktree_dir(wt->gitdir_path)) {
git_error_set(GIT_ERROR_WORKTREE,
- "Worktree gitdir ('%s') is not valid",
+ "worktree gitdir ('%s') is not valid",
wt->gitlink_path);
return GIT_ERROR;
}
if (wt->parent_path && !git_path_exists(wt->parent_path)) {
git_error_set(GIT_ERROR_WORKTREE,
- "Worktree parent directory ('%s') does not exist ",
+ "worktree parent directory ('%s') does not exist ",
wt->parent_path);
return GIT_ERROR;
}
if (!git_path_exists(wt->commondir_path)) {
git_error_set(GIT_ERROR_WORKTREE,
- "Worktree common directory ('%s') does not exist ",
+ "worktree common directory ('%s') does not exist ",
wt->commondir_path);
return GIT_ERROR;
}
return 0;
}
-int git_worktree_add_init_options(git_worktree_add_options *opts,
+int git_worktree_add_options_init(git_worktree_add_options *opts,
unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_worktree_add_init_options(git_worktree_add_options *opts,
+ unsigned int version)
+{
+ return git_worktree_add_options_init(opts, version);
+}
+#endif
+
int git_worktree_add(git_worktree **out, git_repository *repo,
const char *name, const char *worktree,
const git_worktree_add_options *opts)
*out = NULL;
+ if (wtopts.ref) {
+ if (!git_reference_is_branch(wtopts.ref)) {
+ git_error_set(GIT_ERROR_WORKTREE, "reference is not a branch");
+ err = -1;
+ goto out;
+ }
+
+ if (git_branch_is_checked_out(wtopts.ref)) {
+ git_error_set(GIT_ERROR_WORKTREE, "reference is already checked out");
+ err = -1;
+ goto out;
+ }
+ }
+
/* Create gitdir directory ".git/worktrees/<name>" */
if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0)
goto out;
/* Set up worktree reference */
if (wtopts.ref) {
- if (!git_reference_is_branch(wtopts.ref)) {
- git_error_set(GIT_ERROR_WORKTREE, "reference is not a branch");
- err = -1;
- goto out;
- }
-
- if (git_branch_is_checked_out(wtopts.ref)) {
- git_error_set(GIT_ERROR_WORKTREE, "reference is already checked out");
- err = -1;
- goto out;
- }
-
if ((err = git_reference_dup(&ref, wtopts.ref)) < 0)
goto out;
} else {
int git_worktree_lock(git_worktree *wt, const char *reason)
{
git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
- int err;
+ int error;
assert(wt);
- if ((err = git_worktree_is_locked(NULL, wt)) < 0)
+ if ((error = git_worktree_is_locked(NULL, wt)) < 0)
+ goto out;
+ if (error) {
+ error = GIT_ELOCKED;
goto out;
+ }
- if ((err = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
+ if ((error = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
goto out;
if (reason)
git_buf_attach_notowned(&buf, reason, strlen(reason));
- if ((err = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
+ if ((error = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
goto out;
wt->locked = 1;
out:
git_buf_dispose(&path);
- return err;
+ return error;
}
int git_worktree_unlock(git_worktree *wt)
{
git_buf path = GIT_BUF_INIT;
+ int error;
assert(wt);
- if (!git_worktree_is_locked(NULL, wt))
+ if ((error = git_worktree_is_locked(NULL, wt)) < 0)
+ return error;
+ if (!error)
return 1;
if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0)
int git_worktree_is_locked(git_buf *reason, const git_worktree *wt)
{
git_buf path = GIT_BUF_INIT;
- int ret;
+ int error, locked;
assert(wt);
if (reason)
git_buf_clear(reason);
- if ((ret = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
+ if ((error = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
+ goto out;
+ locked = git_path_exists(path.ptr);
+ if (locked && reason &&
+ (error = git_futils_readbuffer(reason, path.ptr)) < 0)
goto out;
- if ((ret = git_path_exists(path.ptr)) && reason)
- git_futils_readbuffer(reason, path.ptr);
+ error = locked;
out:
git_buf_dispose(&path);
- return ret;
+ return error;
}
const char *git_worktree_name(const git_worktree *wt)
return wt->worktree_path;
}
-int git_worktree_prune_init_options(
+int git_worktree_prune_options_init(
git_worktree_prune_options *opts,
unsigned int version)
{
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_worktree_prune_init_options(git_worktree_prune_options *opts,
+ unsigned int version)
+{
+ return git_worktree_prune_options_init(opts, version);
+}
+#endif
+
int git_worktree_is_prunable(git_worktree *wt,
git_worktree_prune_options *opts)
{
- git_buf reason = GIT_BUF_INIT;
git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
GIT_ERROR_CHECK_VERSION(
if (opts)
memcpy(&popts, opts, sizeof(popts));
- if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 &&
- git_worktree_is_locked(&reason, wt))
- {
- if (!reason.size)
- git_buf_attach_notowned(&reason, "no reason given", 15);
- git_error_set(GIT_ERROR_WORKTREE, "Not pruning locked working tree: '%s'", reason.ptr);
- git_buf_dispose(&reason);
+ if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) {
+ git_buf reason = GIT_BUF_INIT;
+ int error;
- return 0;
+ if ((error = git_worktree_is_locked(&reason, wt)) < 0)
+ return error;
+
+ if (error) {
+ if (!reason.size)
+ git_buf_attach_notowned(&reason, "no reason given", 15);
+ git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr);
+ git_buf_dispose(&reason);
+ return 0;
+ }
}
if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 &&
- git_worktree_validate(wt) == 0)
- {
- git_error_set(GIT_ERROR_WORKTREE, "Not pruning valid working tree");
+ git_worktree_validate(wt) == 0) {
+ git_error_set(GIT_ERROR_WORKTREE, "not pruning valid working tree");
return 0;
}
goto out;
if (!git_path_exists(path.ptr))
{
- git_error_set(GIT_ERROR_WORKTREE, "Worktree gitdir '%s' does not exist", path.ptr);
+ git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr);
err = -1;
goto out;
}
git_buf_attach(&path, wtpath, 0);
if (!git_path_exists(path.ptr))
{
- git_error_set(GIT_ERROR_WORKTREE, "Working tree '%s' does not exist", path.ptr);
+ git_error_set(GIT_ERROR_WORKTREE, "working tree '%s' does not exist", path.ptr);
err = -1;
goto out;
}
#elif defined(__GNUC__)
# define XDL_INLINE(type) static __inline__ type
#else
-#define XDG_INLINE(type) static type
+# define XDL_INLINE(type) static type
#endif
typedef struct s_xdpsplit {
status = 0;
if (!xscr1) {
result->ptr = xdl_malloc(mf2->size);
+ if (!result->ptr) {
+ xdl_free_script(xscr2);
+ xdl_free_env(&xe1);
+ xdl_free_env(&xe2);
+ return -1;
+ }
memcpy(result->ptr, mf2->ptr, mf2->size);
result->size = mf2->size;
} else if (!xscr2) {
result->ptr = xdl_malloc(mf1->size);
+ if (!result->ptr) {
+ xdl_free_script(xscr1);
+ xdl_free_env(&xe1);
+ xdl_free_env(&xe2);
+ return -1;
+ }
memcpy(result->ptr, mf1->ptr, mf1->size);
result->size = mf1->size;
} else {
*/
int anchor_i = -1;
+ if (!sequence)
+ return NULL;
+
for (entry = map->first; entry; entry = entry->next) {
if (!entry->line2 || entry->line2 == NON_UNIQUE)
continue;
return (!zstream->in_len && zstream->zerr == Z_STREAM_END);
}
+bool git_zstream_eos(git_zstream *zstream)
+{
+ return zstream->zerr == Z_STREAM_END;
+}
+
size_t git_zstream_suggest_output_len(git_zstream *zstream)
{
if (zstream->in_len > ZSTREAM_BUFFER_SIZE)
int git_zstream_get_output(void *out, size_t *out_len, git_zstream *zstream);
bool git_zstream_done(git_zstream *zstream);
+bool git_zstream_eos(git_zstream *zstream);
void git_zstream_reset(git_zstream *zstream);
SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES C_STANDARD 90)
SET_TARGET_PROPERTIES(libgit2_clar PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_BINARY_DIR})
-IF (${CMAKE_VERSION} VERSION_LESS 2.8.12)
- # Already handled by a global INCLUDE_DIRECTORY()
-ELSE()
- TARGET_INCLUDE_DIRECTORIES(libgit2_clar PRIVATE ../src PUBLIC ../include)
-ENDIF()
-
+TARGET_INCLUDE_DIRECTORIES(libgit2_clar PRIVATE ../src PUBLIC ../include)
TARGET_LINK_LIBRARIES(libgit2_clar ${LIBGIT2_LIBS})
IDE_SPLIT_SOURCES(libgit2_clar)
SET_SOURCE_FILES_PROPERTIES("precompiled.c" COMPILE_FLAGS "/Ycprecompiled.h")
ENDIF ()
-ADD_TEST(offline "${libgit2_BINARY_DIR}/libgit2_clar" -v -xonline)
-ADD_TEST(invasive "${libgit2_BINARY_DIR}/libgit2_clar" -v -score::ftruncate -sfilter::stream::bigfile -sodb::largefiles -siterator::workdir::filesystem_gunk -srepo::init -srepo::init::at_filesystem_root)
-ADD_TEST(online "${libgit2_BINARY_DIR}/libgit2_clar" -v -sonline)
-ADD_TEST(gitdaemon "${libgit2_BINARY_DIR}/libgit2_clar" -v -sonline::push)
-ADD_TEST(ssh "${libgit2_BINARY_DIR}/libgit2_clar" -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths)
-ADD_TEST(proxy "${libgit2_BINARY_DIR}/libgit2_clar" -v -sonline::clone::proxy_credentials_in_url -sonline::clone::proxy_credentials_request)
+FUNCTION(ADD_CLAR_TEST name)
+ IF (NOT USE_LEAK_CHECKER STREQUAL "OFF")
+ ADD_TEST(${name} "${libgit2_SOURCE_DIR}/script/${USE_LEAK_CHECKER}.sh" "${libgit2_BINARY_DIR}/libgit2_clar" ${ARGN})
+ ELSE()
+ ADD_TEST(${name} "${libgit2_BINARY_DIR}/libgit2_clar" ${ARGN})
+ ENDIF()
+ENDFUNCTION(ADD_CLAR_TEST)
+
+ADD_CLAR_TEST(offline -v -xonline)
+ADD_CLAR_TEST(invasive -v -score::ftruncate -sfilter::stream::bigfile -sodb::largefiles -siterator::workdir::filesystem_gunk -srepo::init -srepo::init::at_filesystem_root)
+ADD_CLAR_TEST(online -v -sonline)
+ADD_CLAR_TEST(gitdaemon -v -sonline::push)
+ADD_CLAR_TEST(ssh -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh)
+ADD_CLAR_TEST(proxy -v -sonline::clone::proxy)
+ADD_CLAR_TEST(auth_clone -v -sonline::clone::cred)
+ADD_CLAR_TEST(auth_clone_and_push -v -sonline::clone::push -sonline::push)
* Make sure everything is fine.
* Send your pull request. That's it.
+
+
+Memory leak checks
+------------------
+
+These are automatically run as part of CI, but if you want to check locally:
+
+#### Linux
+
+Uses [`valgrind`](http://www.valgrind.org/):
+
+```console
+$ cmake -DBUILD_CLAR=ON -DVALGRIND=ON ..
+$ cmake --build .
+$ valgrind --leak-check=full --show-reachable=yes --num-callers=50 --suppressions=../libgit2_clar.supp \
+ ./libgit2_clar
+```
+
+#### macOS
+
+Uses [`leaks`](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html), which requires XCode installed:
+
+```console
+$ MallocStackLogging=1 MallocScribble=1 MallocLogFile=/dev/null CLAR_AT_EXIT="leaks -quiet \$PPID" \
+ ./libgit2_clar
+```
"-longer. take out the slices of ham, and skim off the grease if any\n" \
"+longer; take out the slices of ham, and skim off the grease if any\n"
+/* This is the binary equivalent of DIFF_MODIFY_TWO_FILES */
+#define DIFF_MODIFY_TWO_FILES_BINARY \
+ "diff --git a/asparagus.txt b/asparagus.txt\n" \
+ "index f51658077d85f2264fa179b4d0848268cb3475c3..ffb36e513f5fdf8a6ba850a20142676a2ac4807d 100644\n" \
+ "GIT binary patch\n" \
+ "delta 24\n" \
+ "fcmX@ja+-zTF*v|6$k9DCSRvRyG(c}7zYP-rT_OhP\n" \
+ "\n" \
+ "delta 24\n" \
+ "fcmX@ja+-zTF*v|6$k9DCSRvRyG(d49zYP-rT;T@W\n" \
+ "\n" \
+ "diff --git a/veal.txt b/veal.txt\n" \
+ "index 94d2c01087f48213bd157222d54edfefd77c9bba..a7b066537e6be7109abfe4ff97b675d4e077da20 100644\n" \
+ "GIT binary patch\n" \
+ "delta 26\n" \
+ "hcmX@kah!uI%+=9HA=p1OKyM?L03)OIW@$zpW&mXg25bNT\n" \
+ "\n" \
+ "delta 26\n" \
+ "hcmX@kah!uI%+=9HA=p1OKyf3N03)N`W@$zpW&mU#22ub3\n" \
+ "\n"
+
#define DIFF_DELETE_FILE \
"diff --git a/gravy.txt b/gravy.txt\n" \
"deleted file mode 100644\n" \
--- /dev/null
+#include "clar_libgit2.h"
+#include "apply_helpers.h"
+
+static git_repository *repo;
+
+#define TEST_REPO_PATH "merge-recursive"
+
+void test_apply_check__initialize(void)
+{
+ git_oid oid;
+ git_commit *commit;
+
+ repo = cl_git_sandbox_init(TEST_REPO_PATH);
+
+ git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707");
+ cl_git_pass(git_commit_lookup(&commit, repo, &oid));
+ cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL));
+ git_commit_free(commit);
+}
+
+void test_apply_check__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_apply_check__generate_diff(void)
+{
+ git_oid a_oid, b_oid;
+ git_commit *a_commit, *b_commit;
+ git_tree *a_tree, *b_tree;
+ git_diff *diff;
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
+
+ cl_git_pass(git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707"));
+ cl_git_pass(git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f"));
+ cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid));
+ cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid));
+
+ cl_git_pass(git_commit_tree(&a_tree, a_commit));
+ cl_git_pass(git_commit_tree(&b_tree, b_commit));
+
+ opts.flags |= GIT_APPLY_CHECK;
+ cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &diff_opts));
+ cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, &opts));
+
+ validate_index_unchanged(repo);
+ validate_workdir_unchanged(repo);
+
+ git_diff_free(diff);
+ git_tree_free(a_tree);
+ git_tree_free(b_tree);
+ git_commit_free(a_commit);
+ git_commit_free(b_commit);
+}
+
+void test_apply_check__parsed_diff(void)
+{
+ git_diff *diff;
+ git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
+
+ opts.flags |= GIT_APPLY_CHECK;
+ cl_git_pass(git_diff_from_buffer(&diff,
+ DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES)));
+ cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts));
+
+ validate_index_unchanged(repo);
+ validate_workdir_unchanged(repo);
+
+ git_diff_free(diff);
+}
+
+void test_apply_check__binary(void)
+{
+ git_diff *diff;
+ git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
+
+ opts.flags |= GIT_APPLY_CHECK;
+ cl_git_pass(git_diff_from_buffer(&diff,
+ DIFF_MODIFY_TWO_FILES_BINARY,
+ strlen(DIFF_MODIFY_TWO_FILES_BINARY)));
+ cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts));
+
+ validate_index_unchanged(repo);
+ validate_workdir_unchanged(repo);
+
+ git_diff_free(diff);
+}
+
+void test_apply_check__does_not_apply(void)
+{
+ git_diff *diff;
+ git_index *index;
+ git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
+
+ const char *diff_file = DIFF_MODIFY_TWO_FILES;
+
+ struct merge_index_entry index_expected[] = {
+ { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
+ { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
+ { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
+ { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
+ { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
+ };
+ size_t index_expected_cnt = sizeof(index_expected) /
+ sizeof(struct merge_index_entry);
+
+ /* mutate the index */
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_git_pass(git_index_remove(index, "veal.txt", 0));
+ cl_git_pass(git_index_write(index));
+ git_index_free(index);
+
+ opts.flags |= GIT_APPLY_CHECK;
+ cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
+ cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_INDEX, &opts));
+
+ validate_apply_index(repo, index_expected, index_expected_cnt);
+
+ git_diff_free(diff);
+}
PATCH_ORIGINAL_TO_CHANGE_LASTLINE, NULL));
}
+void test_apply_fromdiff__change_middle_and_lastline_nocontext(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_CHANGE_MIDDLE_AND_LASTLINE, "file.txt",
+ PATCH_ORIGINAL_TO_CHANGE_MIDDLE_AND_LASTLINE_NOCONTEXT, &diff_opts));
+}
+
void test_apply_fromdiff__prepend(void)
{
cl_git_pass(apply_buf(
NULL, NULL,
NULL, &binary_opts));
}
+
+void test_apply_fromdiff__patching_correctly_truncates_source(void)
+{
+ git_buf original = GIT_BUF_INIT, patched = GIT_BUF_INIT;
+ git_patch *patch;
+ unsigned int mode;
+ char *path;
+
+ cl_git_pass(git_patch_from_buffers(&patch,
+ "foo\nbar", 7, "file.txt",
+ "foo\nfoo", 7, "file.txt", NULL));
+
+ /*
+ * Previously, we would fail to correctly truncate the source buffer if
+ * the source has more than one line and ends with a non-newline
+ * character. In the following call, we thus truncate the source string
+ * in the middle of the second line. Without the bug fixed, we would
+ * successfully apply the patch to the source and return success. With
+ * the overflow being fixed, we should return an error.
+ */
+ cl_git_fail_with(GIT_EAPPLYFAIL,
+ git_apply__patch(&patched, &path, &mode,
+ "foo\nbar\n", 5, patch, NULL));
+
+ /* Verify that the patch succeeds if we do not truncate */
+ cl_git_pass(git_apply__patch(&patched, &path, &mode,
+ "foo\nbar\n", 7, patch, NULL));
+
+ git_buf_dispose(&original);
+ git_buf_dispose(&patched);
+ git_patch_free(patch);
+ git__free(path);
+}
#include "clar_libgit2.h"
+#include "apply_helpers.h"
#include "../merge/merge_helpers.h"
static git_repository *repo;
git_commit_free(b_commit);
}
+void test_apply_tree__adds_file(void)
+{
+ git_oid a_oid;
+ git_commit *a_commit;
+ git_tree *a_tree;
+ git_diff *diff;
+ git_index *index = NULL;
+
+ struct merge_index_entry expected[] = {
+ { 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
+ { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
+ { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
+ { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
+ { 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" },
+ { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
+ { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
+ };
+
+ git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707");
+
+ cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid));
+
+ cl_git_pass(git_commit_tree(&a_tree, a_commit));
+
+ cl_git_pass(git_diff_from_buffer(&diff,
+ DIFF_ADD_FILE, strlen(DIFF_ADD_FILE)));
+
+ cl_git_pass(git_apply_to_tree(&index, repo, a_tree, diff, NULL));
+ merge_test_index(index, expected, 7);
+
+ git_index_free(index);
+ git_diff_free(diff);
+ git_tree_free(a_tree);
+ git_commit_free(a_commit);
+}
{
switch (expected) {
case EXPECT_TRUE:
- cl_assert_(GIT_ATTR_TRUE(value), name);
+ cl_assert_(GIT_ATTR_IS_TRUE(value), name);
break;
case EXPECT_FALSE:
- cl_assert_(GIT_ATTR_FALSE(value), name);
+ cl_assert_(GIT_ATTR_IS_FALSE(value), name);
break;
case EXPECT_UNDEFINED:
- cl_assert_(GIT_ATTR_UNSPECIFIED(value), name);
+ cl_assert_(GIT_ATTR_IS_UNSPECIFIED(value), name);
break;
case EXPECT_STRING:
assign = get_assign(rule, 0);
cl_assert(assign != NULL);
cl_assert_equal_s("binary", assign->name);
- cl_assert(GIT_ATTR_TRUE(assign->value));
+ cl_assert(GIT_ATTR_IS_TRUE(assign->value));
git_attr_file__free(file);
}
assign = get_assign(rule,0);
cl_assert_equal_s("attr0", assign->name);
cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name));
- cl_assert(GIT_ATTR_TRUE(assign->value));
+ cl_assert(GIT_ATTR_IS_TRUE(assign->value));
rule = get_rule(1);
cl_assert_equal_s("pat1", rule->match.pattern);
cl_assert((rule->match.flags & GIT_ATTR_FNMATCH_HASWILD) != 0);
assign = get_assign(rule,0);
cl_assert_equal_s("attr7", assign->name);
- cl_assert(GIT_ATTR_TRUE(assign->value));
+ cl_assert(GIT_ATTR_IS_TRUE(assign->value));
rule = get_rule(8);
cl_assert_equal_s("pat8 with spaces", rule->match.pattern);
assign = git_attr_rule__lookup_assignment(rule, "multiple");
cl_assert(assign);
cl_assert_equal_s("multiple", assign->name);
- cl_assert(GIT_ATTR_TRUE(assign->value));
+ cl_assert(GIT_ATTR_IS_TRUE(assign->value));
assign = git_attr_rule__lookup_assignment(rule, "single");
cl_assert(assign);
cl_assert_equal_s("single", assign->name);
- cl_assert(GIT_ATTR_FALSE(assign->value));
+ cl_assert(GIT_ATTR_IS_FALSE(assign->value));
assign = git_attr_rule__lookup_assignment(rule, "values");
cl_assert(assign);
cl_assert_equal_s("values", assign->name);
assign = git_attr_rule__lookup_assignment(rule, "again");
cl_assert(assign);
cl_assert_equal_s("again", assign->name);
- cl_assert(GIT_ATTR_TRUE(assign->value));
+ cl_assert(GIT_ATTR_IS_TRUE(assign->value));
assign = git_attr_rule__lookup_assignment(rule, "another");
cl_assert(assign);
cl_assert_equal_s("another", assign->name);
git_attr_file__free(file);
}
-void test_attr_file__check_attr_examples(void)
+static void assert_examples(git_attr_file *file)
{
- git_attr_file *file;
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
- cl_assert_equal_s(cl_fixture("attr/attr3"), file->entry->path);
- cl_assert(file->rules.length == 3);
-
rule = get_rule(0);
cl_assert_equal_s("*.java", rule->match.pattern);
cl_assert(rule->assigns.length == 3);
cl_assert_equal_s("java", assign->value);
assign = git_attr_rule__lookup_assignment(rule, "crlf");
cl_assert_equal_s("crlf", assign->name);
- cl_assert(GIT_ATTR_FALSE(assign->value));
+ cl_assert(GIT_ATTR_IS_FALSE(assign->value));
assign = git_attr_rule__lookup_assignment(rule, "myAttr");
cl_assert_equal_s("myAttr", assign->name);
- cl_assert(GIT_ATTR_TRUE(assign->value));
+ cl_assert(GIT_ATTR_IS_TRUE(assign->value));
assign = git_attr_rule__lookup_assignment(rule, "missing");
cl_assert(assign == NULL);
cl_assert(rule->assigns.length == 1);
assign = get_assign(rule, 0);
cl_assert_equal_s("myAttr", assign->name);
- cl_assert(GIT_ATTR_UNSPECIFIED(assign->value));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(assign->value));
rule = get_rule(2);
cl_assert_equal_s("README", rule->match.pattern);
assign = get_assign(rule, 0);
cl_assert_equal_s("caveat", assign->name);
cl_assert_equal_s("unspecified", assign->value);
+}
+
+void test_attr_file__check_attr_examples(void)
+{
+ git_attr_file *file;
+
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
+ cl_assert_equal_s(cl_fixture("attr/attr3"), file->entry->path);
+ cl_assert(file->rules.length == 3);
+
+ assert_examples(file);
+
+ git_attr_file__free(file);
+}
+
+void test_attr_file__whitespace(void)
+{
+ git_attr_file *file;
+
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr4")));
+ cl_assert_equal_s(cl_fixture("attr/attr4"), file->entry->path);
+ cl_assert(file->rules.length == 3);
+
+ assert_examples(file);
git_attr_file__free(file);
}
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM, "README.md", "diff"));
- cl_assert(GIT_ATTR_UNSPECIFIED(value));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(value));
}
void test_attr_flags__index_vs_workdir(void)
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"README.md", "bar"));
- cl_assert(GIT_ATTR_FALSE(value));
+ cl_assert(GIT_ATTR_IS_FALSE(value));
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"README.txt", "foo"));
- cl_assert(GIT_ATTR_FALSE(value));
+ cl_assert(GIT_ATTR_IS_FALSE(value));
/* index then wd */
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"README.md", "bar"));
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"README.txt", "foo"));
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
}
void test_attr_flags__subdir(void)
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
"sub/sub/README.txt", "again"));
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX,
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
"sub/sub/README.txt", "again"));
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
cl_git_pass(git_attr_get(
&value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE,
+++ /dev/null
-#include "clar_libgit2.h"
-#include "posix.h"
-#include "path.h"
-#include "fileops.h"
-
-static git_repository *g_repo = NULL;
-
-void test_attr_ignore__initialize(void)
-{
- g_repo = cl_git_sandbox_init("attr");
-}
-
-void test_attr_ignore__cleanup(void)
-{
- cl_git_sandbox_cleanup();
- g_repo = NULL;
-}
-
-static void assert_is_ignored_(
- bool expected, const char *filepath, const char *file, int line)
-{
- int is_ignored = 0;
-
- cl_git_expect(
- git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), 0, file, line);
-
- clar__assert_equal(
- file, line, "expected != is_ignored", 1, "%d",
- (int)(expected != 0), (int)(is_ignored != 0));
-}
-#define assert_is_ignored(expected, filepath) \
- assert_is_ignored_(expected, filepath, __FILE__, __LINE__)
-
-void test_attr_ignore__honor_temporary_rules(void)
-{
- cl_git_rewritefile("attr/.gitignore", "/NewFolder\n/NewFolder/NewFolder");
-
- assert_is_ignored(false, "File.txt");
- assert_is_ignored(true, "NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
-}
-
-void test_attr_ignore__allow_root(void)
-{
- cl_git_rewritefile("attr/.gitignore", "/");
-
- assert_is_ignored(false, "File.txt");
- assert_is_ignored(false, "NewFolder");
- assert_is_ignored(false, "NewFolder/NewFolder");
- assert_is_ignored(false, "NewFolder/NewFolder/File.txt");
-}
-
-void test_attr_ignore__ignore_space(void)
-{
- cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder \n/NewFolder/NewFolder");
-
- assert_is_ignored(false, "File.txt");
- assert_is_ignored(true, "NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
-}
-
-void test_attr_ignore__ignore_dir(void)
-{
- cl_git_rewritefile("attr/.gitignore", "dir/\n");
-
- assert_is_ignored(true, "dir");
- assert_is_ignored(true, "dir/file");
-}
-
-void test_attr_ignore__ignore_dir_with_trailing_space(void)
-{
- cl_git_rewritefile("attr/.gitignore", "dir/ \n");
-
- assert_is_ignored(true, "dir");
- assert_is_ignored(true, "dir/file");
-}
-
-void test_attr_ignore__ignore_root(void)
-{
- cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder");
-
- assert_is_ignored(false, "File.txt");
- assert_is_ignored(true, "NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
-}
-
-void test_attr_ignore__full_paths(void)
-{
- cl_git_rewritefile("attr/.gitignore", "Folder/*/Contained");
-
- assert_is_ignored(true, "Folder/Middle/Contained");
- assert_is_ignored(false, "Folder/Middle/More/More/Contained");
-
- cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained");
-
- assert_is_ignored(true, "Folder/Middle/Contained");
- assert_is_ignored(true, "Folder/Middle/More/More/Contained");
-
- cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained/*/Child");
-
- assert_is_ignored(true, "Folder/Middle/Contained/Happy/Child");
- assert_is_ignored(false, "Folder/Middle/Contained/Not/Happy/Child");
- assert_is_ignored(true, "Folder/Middle/More/More/Contained/Happy/Child");
- assert_is_ignored(false, "Folder/Middle/More/More/Contained/Not/Happy/Child");
-}
-
-void test_attr_ignore__more_starstar_cases(void)
-{
- cl_must_pass(p_unlink("attr/.gitignore"));
- cl_git_mkfile(
- "attr/dir/.gitignore",
- "sub/**/*.html\n");
-
- assert_is_ignored(false, "aaa.html");
- assert_is_ignored(false, "dir");
- assert_is_ignored(false, "dir/sub");
- assert_is_ignored(true, "dir/sub/sub2/aaa.html");
- assert_is_ignored(true, "dir/sub/aaa.html");
- assert_is_ignored(false, "dir/aaa.html");
- assert_is_ignored(false, "sub");
- assert_is_ignored(false, "sub/aaa.html");
- assert_is_ignored(false, "sub/sub2/aaa.html");
-}
-
-void test_attr_ignore__leading_stars(void)
-{
- cl_git_rewritefile(
- "attr/.gitignore",
- "*/onestar\n"
- "**/twostars\n"
- "*/parent1/kid1/*\n"
- "**/parent2/kid2/*\n");
-
- assert_is_ignored(true, "dir1/onestar");
- assert_is_ignored(true, "dir1/onestar/child"); /* in ignored dir */
- assert_is_ignored(false, "dir1/dir2/onestar");
-
- assert_is_ignored(true, "dir1/twostars");
- assert_is_ignored(true, "dir1/twostars/child"); /* in ignored dir */
- assert_is_ignored(true, "dir1/dir2/twostars");
- assert_is_ignored(true, "dir1/dir2/twostars/child"); /* in ignored dir */
- assert_is_ignored(true, "dir1/dir2/dir3/twostars");
-
- assert_is_ignored(true, "dir1/parent1/kid1/file");
- assert_is_ignored(true, "dir1/parent1/kid1/file/inside/parent");
- assert_is_ignored(false, "dir1/dir2/parent1/kid1/file");
- assert_is_ignored(false, "dir1/parent1/file");
- assert_is_ignored(false, "dir1/kid1/file");
-
- assert_is_ignored(true, "dir1/parent2/kid2/file");
- assert_is_ignored(true, "dir1/parent2/kid2/file/inside/parent");
- assert_is_ignored(true, "dir1/dir2/parent2/kid2/file");
- assert_is_ignored(true, "dir1/dir2/dir3/parent2/kid2/file");
- assert_is_ignored(false, "dir1/parent2/file");
- assert_is_ignored(false, "dir1/kid2/file");
-}
-
-void test_attr_ignore__globs_and_path_delimiters(void)
-{
- cl_git_rewritefile("attr/.gitignore", "foo/bar/**");
- assert_is_ignored(true, "foo/bar/baz");
- assert_is_ignored(true, "foo/bar/baz/quux");
-
- cl_git_rewritefile("attr/.gitignore", "_*/");
- assert_is_ignored(true, "sub/_test/a/file");
- assert_is_ignored(false, "test_folder/file");
- assert_is_ignored(true, "_test/file");
- assert_is_ignored(true, "_test/a/file");
-
- cl_git_rewritefile("attr/.gitignore", "**/_*/");
- assert_is_ignored(true, "sub/_test/a/file");
- assert_is_ignored(false, "test_folder/file");
- assert_is_ignored(true, "_test/file");
- assert_is_ignored(true, "_test/a/file");
-
- cl_git_rewritefile("attr/.gitignore", "**/_*/foo/bar/*ux");
-
- assert_is_ignored(true, "sub/_test/foo/bar/qux/file");
- assert_is_ignored(true, "_test/foo/bar/qux/file");
- assert_is_ignored(true, "_test/foo/bar/crux/file");
- assert_is_ignored(false, "_test/foo/bar/code/file");
-}
-
-void test_attr_ignore__skip_gitignore_directory(void)
-{
- cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder");
- p_unlink("attr/.gitignore");
- cl_assert(!git_path_exists("attr/.gitignore"));
- p_mkdir("attr/.gitignore", 0777);
- cl_git_mkfile("attr/.gitignore/garbage.txt", "new_file\n");
-
- assert_is_ignored(false, "File.txt");
- assert_is_ignored(true, "NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder");
- assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
-}
-
-void test_attr_ignore__subdirectory_gitignore(void)
-{
- p_unlink("attr/.gitignore");
- cl_assert(!git_path_exists("attr/.gitignore"));
- cl_git_mkfile(
- "attr/.gitignore",
- "file1\n");
- p_mkdir("attr/dir", 0777);
- cl_git_mkfile(
- "attr/dir/.gitignore",
- "file2/\n");
-
- assert_is_ignored(true, "file1");
- assert_is_ignored(true, "dir/file1");
- assert_is_ignored(true, "dir/file2/actual_file"); /* in ignored dir */
- assert_is_ignored(false, "dir/file3");
-}
-
-void test_attr_ignore__expand_tilde_to_homedir(void)
-{
- git_config *cfg;
-
- assert_is_ignored(false, "example.global_with_tilde");
-
- cl_fake_home();
-
- /* construct fake home with fake global excludes */
- cl_git_mkfile("home/globalexclude", "# found me\n*.global_with_tilde\n");
-
- cl_git_pass(git_repository_config(&cfg, g_repo));
- cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexclude"));
- git_config_free(cfg);
-
- git_attr_cache_flush(g_repo); /* must reset to pick up change */
-
- assert_is_ignored(true, "example.global_with_tilde");
-
- cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
-
- cl_fake_home_cleanup(NULL);
-
- git_attr_cache_flush(g_repo); /* must reset to pick up change */
-
- assert_is_ignored(false, "example.global_with_tilde");
-}
-
-/* Ensure that the .gitignore in the subdirectory only affects
- * items in the subdirectory. */
-void test_attr_ignore__gitignore_in_subdir(void)
-{
- cl_git_rmfile("attr/.gitignore");
-
- cl_must_pass(p_mkdir("attr/dir1", 0777));
- cl_must_pass(p_mkdir("attr/dir1/dir2", 0777));
- cl_must_pass(p_mkdir("attr/dir1/dir2/dir3", 0777));
-
- cl_git_mkfile("attr/dir1/dir2/dir3/.gitignore", "dir1/\ndir1/subdir/");
-
- assert_is_ignored(false, "dir1/file");
- assert_is_ignored(false, "dir1/dir2/file");
- assert_is_ignored(false, "dir1/dir2/dir3/file");
- assert_is_ignored(true, "dir1/dir2/dir3/dir1/file");
- assert_is_ignored(true, "dir1/dir2/dir3/dir1/subdir/foo");
-
- if (cl_repo_get_bool(g_repo, "core.ignorecase")) {
- cl_git_mkfile("attr/dir1/dir2/dir3/.gitignore", "DiR1/\nDiR1/subdir/\n");
-
- assert_is_ignored(false, "dir1/file");
- assert_is_ignored(false, "dir1/dir2/file");
- assert_is_ignored(false, "dir1/dir2/dir3/file");
- assert_is_ignored(true, "dir1/dir2/dir3/dir1/file");
- assert_is_ignored(true, "dir1/dir2/dir3/dir1/subdir/foo");
- }
-}
-
-/* Ensure that files do not match folder cases */
-void test_attr_ignore__dont_ignore_files_for_folder(void)
-{
- cl_git_rmfile("attr/.gitignore");
-
- cl_git_mkfile("attr/dir/.gitignore", "test/\n");
-
- /* Create "test" as a file; ensure it is not ignored. */
- cl_git_mkfile("attr/dir/test", "This is a file.");
-
- assert_is_ignored(false, "dir/test");
- if (cl_repo_get_bool(g_repo, "core.ignorecase"))
- assert_is_ignored(false, "dir/TeSt");
-
- /* Create "test" as a directory; ensure it is ignored. */
- cl_git_rmfile("attr/dir/test");
- cl_must_pass(p_mkdir("attr/dir/test", 0777));
-
- assert_is_ignored(true, "dir/test");
- if (cl_repo_get_bool(g_repo, "core.ignorecase"))
- assert_is_ignored(true, "dir/TeSt");
-
- /* Remove "test" entirely; ensure it is not ignored.
- * (As it doesn't exist, it is not a directory.)
- */
- cl_must_pass(p_rmdir("attr/dir/test"));
-
- assert_is_ignored(false, "dir/test");
- if (cl_repo_get_bool(g_repo, "core.ignorecase"))
- assert_is_ignored(false, "dir/TeSt");
-}
-
-void test_attr_ignore__symlink_to_outside(void)
-{
-#ifdef GIT_WIN32
- cl_skip();
-#endif
-
- cl_git_rewritefile("attr/.gitignore", "symlink\n");
- cl_git_mkfile("target", "target");
- cl_git_pass(p_symlink("../target", "attr/symlink"));
- assert_is_ignored(true, "symlink");
- assert_is_ignored(true, "lala/../symlink");
-}
-
-void test_attr_ignore__test(void)
-{
- cl_git_rewritefile("attr/.gitignore",
- "/*/\n"
- "!/src\n");
- assert_is_ignored(false, "src/foo.c");
- assert_is_ignored(false, "src/foo/foo.c");
- assert_is_ignored(false, "README.md");
- assert_is_ignored(true, "dist/foo.o");
- assert_is_ignored(true, "bin/foo");
-}
-
-void test_attr_ignore__unignore_dir_succeeds(void)
-{
- cl_git_rewritefile("attr/.gitignore",
- "*.c\n"
- "!src/*.c\n");
- assert_is_ignored(false, "src/foo.c");
- assert_is_ignored(true, "src/foo/foo.c");
-}
-
-void test_attr_ignore__case_insensitive_unignores_previous_rule(void)
-{
- git_config *cfg;
-
- cl_git_rewritefile("attr/.gitignore",
- "/case\n"
- "!/Case/\n");
-
- cl_git_pass(git_repository_config(&cfg, g_repo));
- cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true));
-
- cl_must_pass(p_mkdir("attr/case", 0755));
- cl_git_mkfile("attr/case/file", "content");
-
- assert_is_ignored(false, "case/file");
-}
-
-void test_attr_ignore__case_sensitive_unignore_does_nothing(void)
-{
- git_config *cfg;
-
- cl_git_rewritefile("attr/.gitignore",
- "/case\n"
- "!/Case/\n");
-
- cl_git_pass(git_repository_config(&cfg, g_repo));
- cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false));
-
- cl_must_pass(p_mkdir("attr/case", 0755));
- cl_git_mkfile("attr/case/file", "content");
-
- assert_is_ignored(true, "case/file");
-}
-
-void test_attr_ignore__ignored_subdirfiles_with_subdir_rule(void)
-{
- cl_git_rewritefile(
- "attr/.gitignore",
- "dir/*\n"
- "!dir/sub1/sub2/**\n");
-
- assert_is_ignored(true, "dir/a.test");
- assert_is_ignored(true, "dir/sub1/a.test");
- assert_is_ignored(true, "dir/sub1/sub2");
-}
-
-void test_attr_ignore__ignored_subdirfiles_with_negations(void)
-{
- cl_git_rewritefile(
- "attr/.gitignore",
- "dir/*\n"
- "!dir/a.test\n");
-
- assert_is_ignored(false, "dir/a.test");
- assert_is_ignored(true, "dir/b.test");
- assert_is_ignored(true, "dir/sub1/c.test");
-}
-
-void test_attr_ignore__negative_directory_rules_only_match_directories(void)
-{
- cl_git_rewritefile(
- "attr/.gitignore",
- "*\n"
- "!/**/\n"
- "!*.keep\n"
- "!.gitignore\n"
- );
-
- assert_is_ignored(true, "src");
- assert_is_ignored(true, "src/A");
- assert_is_ignored(false, "src/");
- assert_is_ignored(false, "src/A.keep");
- assert_is_ignored(false, ".gitignore");
-}
cl_assert(!path.is_dir);
cl_git_pass(git_attr_file__lookup_one(file,&path,"binary",&value));
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
cl_git_pass(git_attr_file__lookup_one(file,&path,"missing",&value));
cl_assert(!value);
cl_git_pass(git_attr_file__new(&file, NULL, 0));
- cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz"));
+ cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz", true));
cl_assert(file->rules.length == 3);
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "clar_libgit2.h"
+
+#include "git2/sys/repository.h"
+#include "attr.h"
+
+static git_repository *g_repo = NULL;
+
+void test_attr_macro__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ g_repo = NULL;
+}
+
+void test_attr_macro__macros(void)
+{
+ const char *names[7] = { "rootattr", "binary", "diff", "crlf", "merge", "text", "frotz" };
+ const char *names2[5] = { "mymacro", "positive", "negative", "rootattr", "another" };
+ const char *names3[3] = { "macro2", "multi2", "multi3" };
+ const char *values[7];
+
+ g_repo = cl_git_sandbox_init("attr");
+
+ cl_git_pass(git_attr_get_many(values, g_repo, 0, "binfile", 7, names));
+
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[1]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[2]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[3]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[4]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[5]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[6]));
+
+ cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 5, names2));
+
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[1]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[2]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
+ cl_assert_equal_s("77", values[4]);
+
+ cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 3, names3));
+
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[1]));
+ cl_assert_equal_s("answer", values[2]);
+}
+
+void test_attr_macro__bad_macros(void)
+{
+ const char *names[6] = { "rootattr", "positive", "negative",
+ "firstmacro", "secondmacro", "thirdmacro" };
+ const char *values[6];
+
+ g_repo = cl_git_sandbox_init("attr");
+
+ cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_bad", 6, names));
+
+ /* these three just confirm that the "mymacro" rule ran */
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[1]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[2]));
+
+ /* file contains:
+ * # let's try some malicious macro defs
+ * [attr]firstmacro -thirdmacro -secondmacro
+ * [attr]secondmacro firstmacro -firstmacro
+ * [attr]thirdmacro secondmacro=hahaha -firstmacro
+ * macro_bad firstmacro secondmacro thirdmacro
+ *
+ * firstmacro assignment list ends up with:
+ * -thirdmacro -secondmacro
+ * secondmacro assignment list expands "firstmacro" and ends up with:
+ * -thirdmacro -secondmacro -firstmacro
+ * thirdmacro assignment don't expand so list ends up with:
+ * secondmacro="hahaha"
+ *
+ * macro_bad assignment list ends up with:
+ * -thirdmacro -secondmacro firstmacro &&
+ * -thirdmacro -secondmacro -firstmacro secondmacro &&
+ * secondmacro="hahaha" thirdmacro
+ *
+ * so summary results should be:
+ * -firstmacro secondmacro="hahaha" thirdmacro
+ */
+ cl_assert(GIT_ATTR_IS_FALSE(values[3]));
+ cl_assert_equal_s("hahaha", values[4]);
+ cl_assert(GIT_ATTR_IS_TRUE(values[5]));
+}
+
+void test_attr_macro__macros_in_root_wd_apply(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(p_mkdir("empty_standard_repo/dir", 0777));
+ cl_git_rewritefile("empty_standard_repo/.gitattributes", "[attr]customattr key=value\n");
+ cl_git_rewritefile("empty_standard_repo/dir/.gitattributes", "file customattr\n");
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "dir/file", "key"));
+ cl_assert_equal_s(value, "value");
+}
+
+void test_attr_macro__changing_macro_in_root_wd_updates_attributes(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_rewritefile("empty_standard_repo/.gitattributes",
+ "[attr]customattr key=first\n"
+ "file customattr\n");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "key"));
+ cl_assert_equal_s(value, "first");
+
+ cl_git_rewritefile("empty_standard_repo/.gitattributes",
+ "[attr]customattr key=second\n"
+ "file customattr\n");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "key"));
+ cl_assert_equal_s(value, "second");
+}
+
+void test_attr_macro__macros_in_subdir_do_not_apply(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(p_mkdir("empty_standard_repo/dir", 0777));
+ cl_git_rewritefile("empty_standard_repo/dir/.gitattributes",
+ "[attr]customattr key=value\n"
+ "file customattr\n");
+
+ /* This should _not_ pass, as macros in subdirectories shall be ignored */
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "dir/file", "key"));
+ cl_assert_equal_p(value, NULL);
+}
+
+void test_attr_macro__adding_macro_succeeds(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_pass(git_attr_add_macro(g_repo, "macro", "key=value"));
+ cl_git_rewritefile("empty_standard_repo/.gitattributes", "file.txt macro\n");
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "key"));
+ cl_assert_equal_s(value, "value");
+}
+
+void test_attr_macro__adding_boolean_macros_succeeds(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_pass(git_attr_add_macro(g_repo, "macro-pos", "positive"));
+ cl_git_pass(git_attr_add_macro(g_repo, "macro-neg", "-negative"));
+ cl_git_rewritefile("empty_standard_repo/.gitattributes", "file.txt macro-pos macro-neg\n");
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "positive"));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "negative"));
+ cl_assert(GIT_ATTR_IS_FALSE(value));
+}
+
+void test_attr_macro__redefining_macro_succeeds(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_pass(git_attr_add_macro(g_repo, "macro", "key=value1"));
+ cl_git_pass(git_attr_add_macro(g_repo, "macro", "key=value2"));
+ cl_git_rewritefile("empty_standard_repo/.gitattributes", "file.txt macro");
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "key"));
+ cl_assert_equal_s(value, "value2");
+}
+
+void test_attr_macro__recursive_macro_resolves(void)
+{
+ const char *value;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_pass(git_attr_add_macro(g_repo, "expandme", "key=value"));
+ cl_git_pass(git_attr_add_macro(g_repo, "macro", "expandme"));
+ cl_git_rewritefile("empty_standard_repo/.gitattributes", "file.txt macro");
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "key"));
+ cl_assert_equal_s(value, "value");
+}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/attr.h"
#include "attr.h"
+#include "sysdir.h"
#include "attr_expect.h"
#include "git2/sys/repository.h"
{
cl_git_sandbox_cleanup();
g_repo = NULL;
+ cl_sandbox_set_search_path_defaults();
}
static struct attr_expected get_one_test_cases[] = {
cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test1", 4, names));
- cl_assert(GIT_ATTR_TRUE(values[0]));
- cl_assert(GIT_ATTR_TRUE(values[1]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[1]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test2", 4, names));
- cl_assert(GIT_ATTR_TRUE(values[0]));
- cl_assert(GIT_ATTR_FALSE(values[1]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[1]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/subdir_test1", 4, names));
- cl_assert(GIT_ATTR_TRUE(values[0]));
- cl_assert(GIT_ATTR_TRUE(values[1]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[1]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
cl_assert_equal_s("yes", values[3]);
}
cl_git_pass(git_attr_get_many(vals, g_repo, 0, "sub/subdir_test1", 4, vals));
- cl_assert(GIT_ATTR_TRUE(vals[0]));
- cl_assert(GIT_ATTR_TRUE(vals[1]));
- cl_assert(GIT_ATTR_UNSPECIFIED(vals[2]));
+ cl_assert(GIT_ATTR_IS_TRUE(vals[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(vals[1]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(vals[2]));
cl_assert_equal_s("yes", vals[3]);
}
const char *value;
cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "foo"));
- cl_assert(GIT_ATTR_TRUE(value));
+ cl_assert(GIT_ATTR_IS_TRUE(value));
cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "bar"));
- cl_assert(GIT_ATTR_UNSPECIFIED(value));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(value));
cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "baz"));
- cl_assert(GIT_ATTR_FALSE(value));
+ cl_assert(GIT_ATTR_IS_FALSE(value));
cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "merge"));
cl_assert_equal_s("filfre", value);
cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "frotz"));
- cl_assert(GIT_ATTR_UNSPECIFIED(value));
-}
-
-void test_attr_repo__macros(void)
-{
- const char *names[5] = { "rootattr", "binary", "diff", "crlf", "frotz" };
- const char *names2[5] = { "mymacro", "positive", "negative", "rootattr", "another" };
- const char *names3[3] = { "macro2", "multi2", "multi3" };
- const char *values[5];
-
- cl_git_pass(git_attr_get_many(values, g_repo, 0, "binfile", 5, names));
-
- cl_assert(GIT_ATTR_TRUE(values[0]));
- cl_assert(GIT_ATTR_TRUE(values[1]));
- cl_assert(GIT_ATTR_FALSE(values[2]));
- cl_assert(GIT_ATTR_FALSE(values[3]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[4]));
-
- cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 5, names2));
-
- cl_assert(GIT_ATTR_TRUE(values[0]));
- cl_assert(GIT_ATTR_TRUE(values[1]));
- cl_assert(GIT_ATTR_FALSE(values[2]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
- cl_assert_equal_s("77", values[4]);
-
- cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 3, names3));
-
- cl_assert(GIT_ATTR_TRUE(values[0]));
- cl_assert(GIT_ATTR_FALSE(values[1]));
- cl_assert_equal_s("answer", values[2]);
-}
-
-void test_attr_repo__bad_macros(void)
-{
- const char *names[6] = { "rootattr", "positive", "negative",
- "firstmacro", "secondmacro", "thirdmacro" };
- const char *values[6];
-
- cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_bad", 6, names));
-
- /* these three just confirm that the "mymacro" rule ran */
- cl_assert(GIT_ATTR_UNSPECIFIED(values[0]));
- cl_assert(GIT_ATTR_TRUE(values[1]));
- cl_assert(GIT_ATTR_FALSE(values[2]));
-
- /* file contains:
- * # let's try some malicious macro defs
- * [attr]firstmacro -thirdmacro -secondmacro
- * [attr]secondmacro firstmacro -firstmacro
- * [attr]thirdmacro secondmacro=hahaha -firstmacro
- * macro_bad firstmacro secondmacro thirdmacro
- *
- * firstmacro assignment list ends up with:
- * -thirdmacro -secondmacro
- * secondmacro assignment list expands "firstmacro" and ends up with:
- * -thirdmacro -secondmacro -firstmacro
- * thirdmacro assignment don't expand so list ends up with:
- * secondmacro="hahaha"
- *
- * macro_bad assignment list ends up with:
- * -thirdmacro -secondmacro firstmacro &&
- * -thirdmacro -secondmacro -firstmacro secondmacro &&
- * secondmacro="hahaha" thirdmacro
- *
- * so summary results should be:
- * -firstmacro secondmacro="hahaha" thirdmacro
- */
- cl_assert(GIT_ATTR_FALSE(values[3]));
- cl_assert_equal_s("hahaha", values[4]);
- cl_assert(GIT_ATTR_TRUE(values[5]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(value));
}
#define CONTENT "I'm going to be dynamically processed\r\n" \
cl_git_pass(git_attr_get_many(values, g_repo, 0, "file.txt", 4, names));
- cl_assert(GIT_ATTR_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
cl_assert_equal_s("foobar", values[1]);
- cl_assert(GIT_ATTR_FALSE(values[2]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[2]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
cl_git_pass(git_attr_get_many(values, g_repo, 0, "trial.txt", 4, names));
- cl_assert(GIT_ATTR_FALSE(values[0]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[0]));
cl_assert_equal_s("barfoo", values[1]);
- cl_assert(GIT_ATTR_UNSPECIFIED(values[2]));
- cl_assert(GIT_ATTR_TRUE(values[3]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[3]));
cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/sub/subdir.txt", 4, names));
- cl_assert(GIT_ATTR_TRUE(values[0]));
+ cl_assert(GIT_ATTR_IS_TRUE(values[0]));
cl_assert_equal_s("foobar", values[1]);
- cl_assert(GIT_ATTR_FALSE(values[2]));
- cl_assert(GIT_ATTR_UNSPECIFIED(values[3]));
+ cl_assert(GIT_ATTR_IS_FALSE(values[2]));
+ cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
+}
+
+void test_attr_repo__sysdir(void)
+{
+ git_buf sysdir = GIT_BUF_INIT;
+ const char *value;
+
+ cl_git_pass(p_mkdir("system", 0777));
+ cl_git_rewritefile("system/gitattributes", "file merge=foo");
+ cl_git_pass(git_buf_joinpath(&sysdir, clar_sandbox_path(), "system"));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, sysdir.ptr));
+ g_repo = cl_git_sandbox_reopen();
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "merge"));
+ cl_assert_equal_s(value, "foo");
+
+ cl_git_pass(p_unlink("system/gitattributes"));
+ cl_git_pass(p_rmdir("system"));
+ git_buf_dispose(&sysdir);
+}
+
+void test_attr_repo__sysdir_with_session(void)
+{
+ const char *values[2], *attrs[2] = { "foo", "bar" };
+ git_buf sysdir = GIT_BUF_INIT;
+ git_attr_session session;
+
+ cl_git_pass(p_mkdir("system", 0777));
+ cl_git_rewritefile("system/gitattributes", "file foo=1 bar=2");
+ cl_git_pass(git_buf_joinpath(&sysdir, clar_sandbox_path(), "system"));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, sysdir.ptr));
+ g_repo = cl_git_sandbox_reopen();
+
+ cl_git_pass(git_attr_session__init(&session, g_repo));
+ cl_git_pass(git_attr_get_many_with_session(values, g_repo, &session, 0, "file", ARRAY_SIZE(attrs), attrs));
+
+ cl_assert_equal_s(values[0], "1");
+ cl_assert_equal_s(values[1], "2");
+
+ cl_git_pass(p_unlink("system/gitattributes"));
+ cl_git_pass(p_rmdir("system"));
+ git_buf_dispose(&sysdir);
+ git_attr_session__free(&session);
+}
+
+void test_attr_repo__rewrite(void)
+{
+ const char *value;
+
+ cl_git_rewritefile("attr/.gitattributes", "file.txt foo=first\n");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
+ cl_assert_equal_s(value, "first");
+
+ cl_git_rewritefile("attr/.gitattributes", "file.txt foo=second\n");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
+ cl_assert_equal_s(value, "second");
+
+ cl_git_rewritefile("attr/.gitattributes", "file.txt other=value\n");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
+ cl_assert_equal_p(value, NULL);
+}
+
+void test_attr_repo__rewrite_sysdir(void)
+{
+ git_buf sysdir = GIT_BUF_INIT;
+ const char *value;
+
+ cl_git_pass(p_mkdir("system", 0777));
+ cl_git_pass(git_buf_joinpath(&sysdir, clar_sandbox_path(), "system"));
+ cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, sysdir.ptr));
+ g_repo = cl_git_sandbox_reopen();
+
+ cl_git_rewritefile("system/gitattributes", "file foo=first");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "foo"));
+ cl_assert_equal_s(value, "first");
+
+ cl_git_rewritefile("system/gitattributes", "file foo=second");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "foo"));
+ cl_assert_equal_s(value, "second");
+
+ git_buf_dispose(&sysdir);
+}
+
+void test_attr_repo__unlink(void)
+{
+ const char *value;
+
+ cl_git_rewritefile("attr/.gitattributes", "file.txt foo=value1\n");
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
+ cl_assert_equal_s(value, "value1");
+
+ cl_git_pass(p_unlink("attr/.gitattributes"));
+
+ cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
+ cl_assert_equal_p(value, NULL);
}
}
if (hunk->final_start_line_number != start_line) {
- hunk_message(idx, hunk, "mismatched start line number: expected %d, got %d",
+ hunk_message(idx, hunk, "mismatched start line number: expected %"PRIuZ", got %"PRIuZ,
start_line, hunk->final_start_line_number);
}
cl_assert_equal_i(hunk->final_start_line_number, start_line);
if (hunk->lines_in_hunk != len) {
- hunk_message(idx, hunk, "mismatched line count: expected %d, got %d",
+ hunk_message(idx, hunk, "mismatched line count: expected %"PRIuZ", got %"PRIuZ,
len, hunk->lines_in_hunk);
}
cl_assert_equal_i(hunk->lines_in_hunk, len);
#include "clar_libgit2.h"
#include "blame.h"
-void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...);
+void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...) GIT_FORMAT_PRINTF(3, 4);
void check_blame_hunk_index(
git_repository *repo,
git_repository_free(g_repo);
}
+void test_blame_buffer__index(void)
+{
+ const git_blame_hunk *hunk;
+ const char *buffer = "Hello\nWorld!";
+
+ /*
+ * We need to open a different file from the ones used in other tests. Close
+ * the one opened in test_blame_buffer__initialize() to avoid a leak.
+ */
+ git_blame_free(g_fileblame);
+ g_fileblame = NULL;
+ cl_git_pass(git_blame_file(&g_fileblame, g_repo, "file.txt", NULL));
+
+ cl_git_pass(git_blame_buffer(&g_bufferblame, g_fileblame, buffer, strlen(buffer)));
+ cl_assert_equal_i(2, git_blame_get_hunk_count(g_bufferblame));
+
+ check_blame_hunk_index(g_repo, g_bufferblame, 0, 1, 1, 0, "836bc00b", "file.txt");
+ hunk = git_blame_get_hunk_byline(g_bufferblame, 1);
+ cl_assert(hunk);
+ cl_assert_equal_s("lhchavez", hunk->final_signature->name);
+ check_blame_hunk_index(g_repo, g_bufferblame, 1, 2, 1, 0, "00000000", "file.txt");
+ hunk = git_blame_get_hunk_byline(g_bufferblame, 2);
+ cl_assert(hunk);
+ cl_assert(hunk->final_signature == NULL);
+}
+
void test_blame_buffer__added_line(void)
{
const git_blame_hunk *hunk;
check_blame_hunk_index(g_repo, g_blame, 49, 60, 1, 0, "d12299fe", "src/git.h");
}
+/* This was leading to segfaults on some systems during cache eviction. */
+void test_blame_simple__trivial_libgit2_under_cache_pressure(void)
+{
+ ssize_t old_max_storage = git_cache__max_storage;
+ git_cache__max_storage = 1024 * 1024;
+ test_blame_simple__trivial_libgit2();
+ git_cache__max_storage = old_max_storage;
+}
/*
* $ git blame -n b.txt -L 8
check_blame_hunk_index(g_repo, g_blame, 1, 11, 5, 0, "aa06ecca", "b.txt");
}
+/*
+ * $ git blame -n c.txt
+ * orig line no final line no
+ * commit V author timestamp V
+ * 702c7aa5 1 (Carl Schwan 2020-01-29 01:52:31 +0100 4
+ */
+void test_blame_simple__can_ignore_whitespace_change(void)
+{
+ git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
+
+ cl_git_pass(git_repository_open(&g_repo, cl_fixture("blametest.git")));
+
+ opts.flags |= GIT_BLAME_IGNORE_WHITESPACE;
+ cl_git_pass(git_blame_file(&g_blame, g_repo, "c.txt", &opts));
+ cl_assert_equal_i(1, git_blame_get_hunk_count(g_blame));
+ check_blame_hunk_index(g_repo, g_blame, 0, 1, 4, 0, "702c7aa5", "c.txt");
+}
+
/*
* $ git blame -n b.txt -L ,6
* orig line no final line no
#include "refs.h"
#include "repo/repo_helpers.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo;
#include "clar_libgit2.h"
#include "checkout_helpers.h"
#include "refs.h"
-#include "fileops.h"
+#include "futils.h"
#include "index.h"
void assert_on_branch(git_repository *repo, const char *branch)
#include "clar_libgit2.h"
#include "git2/repository.h"
#include "git2/sys/index.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
static git_repository *g_repo;
{
int symlinks;
- cl_git_pass(git_repository__cvar(&symlinks, repo, GIT_CVAR_SYMLINKS));
+ cl_git_pass(git_repository__configmap_lookup(&symlinks, repo, GIT_CONFIGMAP_SYMLINKS));
if (!symlinks) {
ensure_workdir_contents(path, target);
#include "clar_libgit2.h"
#include "checkout_helpers.h"
#include "../filter/crlf.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/checkout.h"
#include "repository.h"
git_buf details = GIT_BUF_INIT;
git_buf_printf(&details, "filename=%s, system=%s, autocrlf=%s, attrs={%s}",
git_path_basename(actual_path->ptr), systype, cd->autocrlf, cd->attrs);
- clar__fail(__FILE__, __LINE__,
+ clar__fail(__FILE__, __func__, __LINE__,
"checked out contents did not match expected", details.ptr, 0);
git_buf_dispose(&details);
}
#include "refs.h"
#include "repo/repo_helpers.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo;
cl_assert(git_path_isfile("testrepo/tracked/subdir/untracked"));
}
+void test_checkout_head__do_remove_untracked_paths(void)
+{
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_index *index;
+ char *paths[] = {"tracked/untracked"};
+
+ cl_git_pass(p_mkdir("testrepo/tracked", 0755));
+ cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755));
+ cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
+ cl_git_mkfile("testrepo/tracked/untracked", "untracked\n");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
+ cl_git_pass(git_index_write(index));
+
+ git_index_free(index);
+
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
+ opts.paths.strings = paths;
+ opts.paths.count = 1;
+ cl_git_pass(git_checkout_head(g_repo, &opts));
+
+ cl_assert(git_path_isfile("testrepo/tracked/tracked"));
+ cl_assert(!git_path_isfile("testrepo/tracked/untracked"));
+}
+
void test_checkout_head__do_remove_tracked_subdir(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
cl_git_pass(git_reference_name_to_id(&id, repo, "refs/heads/dir"));
cl_git_pass(git_object_lookup(&obj, repo, &id, GIT_OBJECT_ANY));
- git_checkout_init_options(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION);
+ git_checkout_options_init(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION);
checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
}
{
int symlinks;
- cl_git_pass(git_repository__cvar(&symlinks, repo, GIT_CVAR_SYMLINKS));
+ cl_git_pass(git_repository__configmap_lookup(&symlinks, repo, GIT_CONFIGMAP_SYMLINKS));
if (symlinks)
return p_symlink(a, b);
#include "checkout_helpers.h"
#include "git2/checkout.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
#include "remote.h"
#include "repo/repo_helpers.h"
cl_assert_equal_i(false, git_path_isdir("./testrepo/dir"));
}
+void test_checkout_index__can_disable_pathspec_match(void)
+{
+ char *files_to_checkout[] = { "test10.txt", "test11.txt"};
+ git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+ git_object *objects;
+ git_index *index;
+
+ /* reset to beginning of history (i.e. just a README file) */
+ opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
+
+ cl_git_pass(git_revparse_single(&objects, g_repo, "8496071c1b46c854b31185ea97743be6a8774479"));
+ cl_git_pass(git_checkout_tree(g_repo, objects, &opts));
+ cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(objects)));
+ git_object_free(objects);
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ /* We create 4 files and commit them */
+ cl_git_mkfile("testrepo/test9.txt", "original\n");
+ cl_git_mkfile("testrepo/test10.txt", "original\n");
+ cl_git_mkfile("testrepo/test11.txt", "original\n");
+ cl_git_mkfile("testrepo/test12.txt", "original\n");
+
+ cl_git_pass(git_index_add_bypath(index, "test9.txt"));
+ cl_git_pass(git_index_add_bypath(index, "test10.txt"));
+ cl_git_pass(git_index_add_bypath(index, "test11.txt"));
+ cl_git_pass(git_index_add_bypath(index, "test12.txt"));
+ cl_git_pass(git_index_write(index));
+
+ cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "commit our test files");
+
+ /* We modify the content of all 4 of our files */
+ cl_git_rewritefile("testrepo/test9.txt", "modified\n");
+ cl_git_rewritefile("testrepo/test10.txt", "modified\n");
+ cl_git_rewritefile("testrepo/test11.txt", "modified\n");
+ cl_git_rewritefile("testrepo/test12.txt", "modified\n");
+
+ /* We checkout only test10.txt and test11.txt */
+ opts.checkout_strategy =
+ GIT_CHECKOUT_FORCE |
+ GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH;
+ opts.paths.strings = files_to_checkout;
+ opts.paths.count = ARRAY_SIZE(files_to_checkout);
+ cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
+
+ /* The only files that have been reverted to their original content
+ should be test10.txt and test11.txt */
+ check_file_contents("testrepo/test9.txt", "modified\n");
+ check_file_contents("testrepo/test10.txt", "original\n");
+ check_file_contents("testrepo/test11.txt", "original\n");
+ check_file_contents("testrepo/test12.txt", "modified\n");
+
+ git_index_free(index);
+}
+
void test_checkout_index__honor_the_specified_pathspecs(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
static void populate_symlink_workdir(void)
{
+ git_buf path = GIT_BUF_INIT;
git_repository *repo;
git_remote *origin;
git_object *target;
const char *url = git_repository_path(g_repo);
- cl_git_pass(git_repository_init(&repo, "../symlink.git", true));
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), "symlink.git"));
+ cl_git_pass(git_repository_init(&repo, path.ptr, true));
cl_git_pass(git_repository_set_workdir(repo, "symlink", 1));
/* Delete the `origin` repo (if it exists) so we can recreate it. */
cl_git_pass(git_revparse_single(&target, repo, "remotes/origin/master"));
cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL));
+
git_object_free(target);
git_repository_free(repo);
+ git_buf_dispose(&path);
}
void test_checkout_index__honor_coresymlinks_default_true(void)
cl_must_pass(p_mkdir("symlink", 0777));
- if (!filesystem_supports_symlinks("symlink/test"))
+ if (!git_path_supports_symlinks("symlink/test"))
cl_skip();
#ifdef GIT_WIN32
* supports symlinks. Bail entirely on POSIX platforms that
* do support symlinks.
*/
- if (filesystem_supports_symlinks("symlink/test"))
+ if (git_path_supports_symlinks("symlink/test"))
cl_skip();
#endif
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
- if (filesystem_supports_symlinks("testrepo/test")) {
+ if (git_path_supports_symlinks("testrepo/test")) {
cl_skip();
}
char link_data[GIT_PATH_MAX];
size_t link_size = GIT_PATH_MAX;
- if (!filesystem_supports_symlinks("testrepo/test")) {
+ if (!git_path_supports_symlinks("testrepo/test")) {
cl_skip();
}
#include "git2/checkout.h"
#include "repository.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
static const char *repo_name = "nasty";
static git_repository *repo;
#include "git2/checkout.h"
#include "repository.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo;
static git_checkout_options g_opts;
{
/* A utf-8 string with 83 characters, but 249 bytes. */
const char *longname = "\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97\xe5\x8f\x97";
- char path[1024];
+ char path[1024] = {0};
g_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_pass(git_revparse_single(&g_object, g_repo, "long-file-name"));
#include "git2/checkout.h"
#include "path.h"
#include "posix.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo = NULL;
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/cherrypick.h"
#include "../merge/merge_helpers.h"
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/cherrypick.h"
#include "../merge/merge_helpers.h"
# define PRIxZ "Ix"
# endif
-# ifdef _MSC_VER
+# if defined(_MSC_VER) || defined(__MINGW32__)
typedef struct stat STAT_T;
# else
typedef struct _stat STAT_T;
struct clar_error {
const char *file;
- int line_number;
+ const char *function;
+ size_t line_number;
const char *error_msg;
char *description;
int tests_ran;
int suites_ran;
+ enum cl_output_format output_format;
+
int report_errors_only;
int exit_on_error;
int report_suite_names;
int write_summary;
- const char *summary_filename;
+ char *summary_filename;
struct clar_summary *summary;
struct clar_explicit *explicit;
const struct clar_func *test = suite->tests;
size_t i, matchlen;
struct clar_report *report;
+ int exact = 0;
if (!suite->enabled)
return;
while (*filter == ':')
++filter;
matchlen = strlen(filter);
+
+ if (matchlen && filter[matchlen - 1] == '$') {
+ exact = 1;
+ matchlen--;
+ }
}
}
if (filter && strncmp(test[i].name, filter, matchlen))
continue;
+ if (exact && strlen(test[i].name) != matchlen)
+ continue;
+
_clar.active_test = test[i].name;
report = calloc(1, sizeof(struct clar_report));
printf(" -v Increase verbosity (show suite names)\n");
printf(" -q Only report tests that had an error\n");
printf(" -Q Quit as soon as a test fails\n");
+ printf(" -t Display results in tap format\n");
printf(" -l Print suite names\n");
printf(" -r[filename] Write summary file (to the optional filename)\n");
exit(-1);
char *argument = argv[i];
if (argument[0] != '-' || argument[1] == '\0'
- || strchr("sixvqQlr", argument[1]) == NULL) {
+ || strchr("sixvqQtlr", argument[1]) == NULL) {
clar_usage(argv[0]);
}
}
_clar.exit_on_error = 1;
break;
+ case 't':
+ _clar.output_format = CL_OUTPUT_TAP;
+ break;
+
case 'l': {
size_t j;
printf("Test suites (use -s<name> to run just one):\n");
case 'r':
_clar.write_summary = 1;
- _clar.summary_filename = *(argument + 2) ? (argument + 2) :
- "summary.xml";
+ free(_clar.summary_filename);
+ _clar.summary_filename = strdup(*(argument + 2) ? (argument + 2) : "summary.xml");
break;
default:
void
clar_test_init(int argc, char **argv)
{
+ if (argc > 1)
+ clar_parse_args(argc, argv);
+
clar_print_init(
(int)_clar_callback_count,
(int)_clar_suite_count,
""
);
- if (argc > 1)
- clar_parse_args(argc, argv);
+ if ((_clar.summary_filename = getenv("CLAR_SUMMARY")) != NULL) {
+ _clar.write_summary = 1;
+ _clar.summary_filename = strdup(_clar.summary_filename);
+ }
if (_clar.write_summary &&
!(_clar.summary = clar_summary_init(_clar.summary_filename))) {
report_next = report->next;
free(report);
}
+
+ free(_clar.summary_filename);
}
int
void clar__fail(
const char *file,
- int line,
+ const char *function,
+ size_t line,
const char *error_msg,
const char *description,
int should_abort)
_clar.last_report->last_error = error;
error->file = file;
+ error->function = function;
error->line_number = line;
error->error_msg = error_msg;
void clar__assert(
int condition,
const char *file,
- int line,
+ const char *function,
+ size_t line,
const char *error_msg,
const char *description,
int should_abort)
if (condition)
return;
- clar__fail(file, line, error_msg, description, should_abort);
+ clar__fail(file, function, line, error_msg, description, should_abort);
}
void clar__assert_equal(
const char *file,
- int line,
+ const char *function,
+ size_t line,
const char *err,
int should_abort,
const char *fmt,
va_end(args);
if (!is_equal)
- clar__fail(file, line, err, buf, should_abort);
+ clar__fail(file, function, line, err, buf, should_abort);
}
void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
CL_TEST_NOTRUN,
};
+enum cl_output_format {
+ CL_OUTPUT_CLAP,
+ CL_OUTPUT_TAP,
+};
+
/** Setup clar environment */
void clar_test_init(int argc, char *argv[]);
int clar_test_run(void);
/**
* Assertion macros with explicit error message
*/
-#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1)
-#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
-#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1)
+#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 1)
+#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
+#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 1)
/**
* Check macros with explicit error message
*/
-#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0)
-#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
-#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0)
+#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __func__, __LINE__, "Function call failed: " #expr, desc, 0)
+#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __func__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
+#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __func__, __LINE__, "Expression is not true: " #expr, desc, 0)
/**
* Assertion macros with no error message
/**
* Forced failure/warning
*/
-#define cl_fail(desc) clar__fail(__FILE__, __LINE__, "Test failed.", desc, 1)
-#define cl_warning(desc) clar__fail(__FILE__, __LINE__, "Warning during test execution:", desc, 0)
+#define cl_fail(desc) clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1)
+#define cl_warning(desc) clar__fail(__FILE__, __func__, __LINE__, "Warning during test execution:", desc, 0)
#define cl_skip() clar__skip()
/**
* Typed assertion macros
*/
-#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2))
-#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2))
+#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2))
+#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2))
-#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2))
-#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2))
+#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2))
+#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2))
-#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len))
-#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len))
+#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len))
+#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len))
-#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
-#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
+#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
+#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__func__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
-#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
-#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
-#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
+#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
+#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
+#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__func__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
-#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
+#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__func__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
-#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2))
+#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__func__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2))
void clar__skip(void);
void clar__fail(
const char *file,
- int line,
+ const char *func,
+ size_t line,
const char *error,
const char *description,
int should_abort);
void clar__assert(
int condition,
const char *file,
- int line,
+ const char *func,
+ size_t line,
const char *error,
const char *description,
int should_abort);
void clar__assert_equal(
const char *file,
- int line,
+ const char *func,
+ size_t line,
const char *err,
int should_abort,
const char *fmt,
+/*
+ * By default, use a read/write loop to copy files on POSIX systems.
+ * On Linux, use sendfile by default as it's slightly faster. On
+ * macOS, we avoid fcopyfile by default because it's slightly slower.
+ */
+#undef USE_FCOPYFILE
+#define USE_SENDFILE 1
+
#ifdef _WIN32
#define RM_RETRY_COUNT 5
#include <errno.h>
#include <string.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(__linux__)
+# include <sys/sendfile.h>
+#endif
-static int
-shell_out(char * const argv[])
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
+static void basename_r(const char **out, int *out_len, const char *in)
{
- int status, piderr;
- pid_t pid;
+ size_t in_len = strlen(in), start_pos;
+
+ for (in_len = strlen(in); in_len; in_len--) {
+ if (in[in_len - 1] != '/')
+ break;
+ }
+
+ for (start_pos = in_len; start_pos; start_pos--) {
+ if (in[start_pos - 1] == '/')
+ break;
+ }
- pid = fork();
+ cl_assert(in_len - start_pos < INT_MAX);
- if (pid < 0) {
- fprintf(stderr,
- "System error: `fork()` call failed (%d) - %s\n",
- errno, strerror(errno));
- exit(-1);
+ if (in_len - start_pos > 0) {
+ *out = &in[start_pos];
+ *out_len = (in_len - start_pos);
+ } else {
+ *out = "/";
+ *out_len = 1;
}
+}
+
+static char *joinpath(const char *dir, const char *base, int base_len)
+{
+ char *out;
+ int len;
- if (pid == 0) {
- execv(argv[0], argv);
+ if (base_len == -1) {
+ size_t bl = strlen(base);
+
+ cl_assert(bl < INT_MAX);
+ base_len = (int)bl;
}
- do {
- piderr = waitpid(pid, &status, WUNTRACED);
- } while (piderr < 0 && (errno == EAGAIN || errno == EINTR));
+ len = strlen(dir) + base_len + 2;
+ cl_assert(len > 0);
+
+ cl_assert(out = malloc(len));
+ cl_assert(snprintf(out, len, "%s/%.*s", dir, base_len, base) < len);
+
+ return out;
+}
+
+static void
+fs_copydir_helper(const char *source, const char *dest, int dest_mode)
+{
+ DIR *source_dir;
+ struct dirent *d;
+
+ mkdir(dest, dest_mode);
+
+ cl_assert_(source_dir = opendir(source), "Could not open source dir");
+ while ((d = (errno = 0, readdir(source_dir))) != NULL) {
+ char *child;
+
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ child = joinpath(source, d->d_name, -1);
+ fs_copy(child, dest);
+ free(child);
+ }
+
+ cl_assert_(errno == 0, "Failed to iterate source dir");
+
+ closedir(source_dir);
+}
+
+static void
+fs_copyfile_helper(const char *source, size_t source_len, const char *dest, int dest_mode)
+{
+ int in, out;
+
+ cl_must_pass((in = open(source, O_RDONLY)));
+ cl_must_pass((out = open(dest, O_WRONLY|O_CREAT|O_TRUNC, dest_mode)));
+
+#if USE_FCOPYFILE && defined(__APPLE__)
+ ((void)(source_len)); /* unused */
+ cl_must_pass(fcopyfile(in, out, 0, COPYFILE_DATA));
+#elif USE_SENDFILE && defined(__linux__)
+ {
+ ssize_t ret = 0;
+
+ while (source_len && (ret = sendfile(out, in, NULL, source_len)) > 0) {
+ source_len -= (size_t)ret;
+ }
+ cl_assert(ret >= 0);
+ }
+#else
+ {
+ char buf[131072];
+ ssize_t ret;
+
+ ((void)(source_len)); /* unused */
- return WEXITSTATUS(status);
+ while ((ret = read(in, buf, sizeof(buf))) > 0) {
+ size_t len = (size_t)ret;
+
+ while (len && (ret = write(out, buf, len)) > 0) {
+ cl_assert(ret <= (ssize_t)len);
+ len -= ret;
+ }
+ cl_assert(ret >= 0);
+ }
+ cl_assert(ret == 0);
+ }
+#endif
+
+ close(in);
+ close(out);
}
static void
-fs_copy(const char *_source, const char *dest)
+fs_copy(const char *source, const char *_dest)
{
- char *argv[5];
- char *source;
- size_t source_len;
+ char *dbuf = NULL;
+ const char *dest;
+ struct stat source_st, dest_st;
+
+ cl_must_pass_(lstat(source, &source_st), "Failed to stat copy source");
- source = strdup(_source);
- source_len = strlen(source);
+ if (lstat(_dest, &dest_st) == 0) {
+ const char *base;
+ int base_len;
- if (source[source_len - 1] == '/')
- source[source_len - 1] = 0;
+ /* Target exists and is directory; append basename */
+ cl_assert(S_ISDIR(dest_st.st_mode));
- argv[0] = "/bin/cp";
- argv[1] = "-R";
- argv[2] = source;
- argv[3] = (char *)dest;
- argv[4] = NULL;
+ basename_r(&base, &base_len, source);
+ cl_assert(base_len < INT_MAX);
- cl_must_pass_(
- shell_out(argv),
- "Failed to copy test fixtures to sandbox"
- );
+ dbuf = joinpath(_dest, base, base_len);
+ dest = dbuf;
+ } else if (errno != ENOENT) {
+ cl_fail("Cannot copy; cannot stat destination");
+ } else {
+ dest = _dest;
+ }
- free(source);
+ if (S_ISDIR(source_st.st_mode)) {
+ fs_copydir_helper(source, dest, source_st.st_mode);
+ } else {
+ fs_copyfile_helper(source, source_st.st_size, dest, source_st.st_mode);
+ }
+
+ free(dbuf);
}
static void
-fs_rm(const char *source)
+fs_rmdir_helper(const char *path)
{
- char *argv[4];
+ DIR *dir;
+ struct dirent *d;
+
+ cl_assert_(dir = opendir(path), "Could not open dir");
+ while ((d = (errno = 0, readdir(dir))) != NULL) {
+ char *child;
+
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
- argv[0] = "/bin/rm";
- argv[1] = "-Rf";
- argv[2] = (char *)source;
- argv[3] = NULL;
+ child = joinpath(path, d->d_name, -1);
+ fs_rm(child);
+ free(child);
+ }
+
+ cl_assert_(errno == 0, "Failed to iterate source dir");
+ closedir(dir);
+
+ cl_must_pass_(rmdir(path), "Could not remove directory");
+}
- cl_must_pass_(
- shell_out(argv),
- "Failed to cleanup the sandbox"
- );
+static void
+fs_rm(const char *path)
+{
+ struct stat st;
+
+ if (lstat(path, &st)) {
+ if (errno == ENOENT)
+ return;
+
+ cl_fail("Cannot copy; cannot stat destination");
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ fs_rmdir_helper(path);
+ } else {
+ cl_must_pass(unlink(path));
+ }
}
void
+/* clap: clar protocol, the traditional clar output format */
-static void clar_print_init(int test_count, int suite_count, const char *suite_names)
+static void clar_print_clap_init(int test_count, int suite_count, const char *suite_names)
{
(void)test_count;
printf("Loaded %d suites: %s\n", (int)suite_count, suite_names);
printf("Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')\n");
}
-static void clar_print_shutdown(int test_count, int suite_count, int error_count)
+static void clar_print_clap_shutdown(int test_count, int suite_count, int error_count)
{
(void)test_count;
(void)suite_count;
clar_report_all();
}
-static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error)
+static void clar_print_clap_error(int num, const struct clar_report *report, const struct clar_error *error)
{
printf(" %d) Failure:\n", num);
- printf("%s::%s [%s:%d]\n",
+ printf("%s::%s [%s:%"PRIuZ"]\n",
report->suite,
report->test,
error->file,
fflush(stdout);
}
-static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status status)
+static void clar_print_clap_ontest(const char *test_name, int test_number, enum cl_test_status status)
{
(void)test_name;
(void)test_number;
fflush(stdout);
}
-static void clar_print_onsuite(const char *suite_name, int suite_index)
+static void clar_print_clap_onsuite(const char *suite_name, int suite_index)
{
if (_clar.report_suite_names)
printf("\n%s", suite_name);
(void)suite_index;
}
+static void clar_print_clap_onabort(const char *fmt, va_list arg)
+{
+ vfprintf(stderr, fmt, arg);
+}
+
+/* tap: test anywhere protocol format */
+
+static void clar_print_tap_init(int test_count, int suite_count, const char *suite_names)
+{
+ (void)test_count;
+ (void)suite_count;
+ (void)suite_names;
+ printf("TAP version 13\n");
+}
+
+static void clar_print_tap_shutdown(int test_count, int suite_count, int error_count)
+{
+ (void)suite_count;
+ (void)error_count;
+
+ printf("1..%d\n", test_count);
+}
+
+static void clar_print_tap_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+ (void)num;
+ (void)report;
+ (void)error;
+}
+
+static void print_escaped(const char *str)
+{
+ char *c;
+
+ while ((c = strchr(str, '\'')) != NULL) {
+ printf("%.*s", (int)(c - str), str);
+ printf("''");
+ str = c + 1;
+ }
+
+ printf("%s", str);
+}
+
+static void clar_print_tap_ontest(const char *test_name, int test_number, enum cl_test_status status)
+{
+ const struct clar_error *error = _clar.last_report->errors;
+
+ (void)test_name;
+ (void)test_number;
+
+ switch(status) {
+ case CL_TEST_OK:
+ printf("ok %d - %s::%s\n", test_number, _clar.active_suite, test_name);
+ break;
+ case CL_TEST_FAILURE:
+ printf("not ok %d - %s::%s\n", test_number, _clar.active_suite, test_name);
+
+ printf(" ---\n");
+ printf(" reason: |\n");
+ printf(" %s\n", error->error_msg);
+
+ if (error->description)
+ printf(" %s\n", error->description);
+
+ printf(" at:\n");
+ printf(" file: '"); print_escaped(error->file); printf("'\n");
+ printf(" line: %" PRIuZ "\n", error->line_number);
+ printf(" function: '%s'\n", error->function);
+ printf(" ---\n");
+
+ break;
+ case CL_TEST_SKIP:
+ case CL_TEST_NOTRUN:
+ printf("ok %d - # SKIP %s::%s\n", test_number, _clar.active_suite, test_name);
+ break;
+ }
+
+ fflush(stdout);
+}
+
+static void clar_print_tap_onsuite(const char *suite_name, int suite_index)
+{
+ printf("# start of suite %d: %s\n", suite_index, suite_name);
+}
+
+static void clar_print_tap_onabort(const char *fmt, va_list arg)
+{
+ printf("Bail out! ");
+ vprintf(fmt, arg);
+ fflush(stdout);
+}
+
+/* indirection between protocol output selection */
+
+#define PRINT(FN, ...) do { \
+ switch (_clar.output_format) { \
+ case CL_OUTPUT_CLAP: \
+ clar_print_clap_##FN (__VA_ARGS__); \
+ break; \
+ case CL_OUTPUT_TAP: \
+ clar_print_tap_##FN (__VA_ARGS__); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ } while (0)
+
+static void clar_print_init(int test_count, int suite_count, const char *suite_names)
+{
+ PRINT(init, test_count, suite_count, suite_names);
+}
+
+static void clar_print_shutdown(int test_count, int suite_count, int error_count)
+{
+ PRINT(shutdown, test_count, suite_count, error_count);
+}
+
+static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error)
+{
+ PRINT(error, num, report, error);
+}
+
+static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status status)
+{
+ PRINT(ontest, test_name, test_number, status);
+}
+
+static void clar_print_onsuite(const char *suite_name, int suite_index)
+{
+ PRINT(onsuite, suite_name, suite_index);
+}
+
static void clar_print_onabort(const char *msg, ...)
{
va_list argp;
va_start(argp, msg);
- vfprintf(stderr, msg, argp);
+ PRINT(onabort, msg, argp);
va_end(argp);
}
#include "git2/sys/repository.h"
void cl_git_report_failure(
- int error, int expected, const char *file, int line, const char *fncall)
+ int error, int expected, const char *file, const char *func, int line, const char *fncall)
{
char msg[4096];
const git_error *last = git_error_last();
else
p_snprintf(msg, 4096, "no error, expected non-zero return");
- clar__assert(0, file, line, fncall, msg, 1);
+ clar__assert(0, file, func, line, fncall, msg, 1);
}
void cl_git_mkfile(const char *filename, const char *content)
int ignore_cr,
const char *path,
const char *file,
+ const char *func,
int line)
{
char buf[4000];
while ((bytes = p_read(fd, buf, sizeof(buf))) != 0) {
clar__assert(
- bytes > 0, file, line, "error reading from file", path, 1);
+ bytes > 0, file, func, line, "error reading from file", path, 1);
if (ignore_cr)
bytes = strip_cr_from_buf(buf, bytes);
buf, sizeof(buf), "file content mismatch at byte %"PRIdZ,
(ssize_t)(total_bytes + pos));
p_close(fd);
- clar__fail(file, line, path, buf, 1);
+ clar__fail(file, func, line, path, buf, 1);
}
expected_data += bytes;
p_close(fd);
- clar__assert(!bytes, file, line, "error reading from file", path, 1);
- clar__assert_equal(file, line, "mismatched file length", 1, "%"PRIuZ,
+ clar__assert(!bytes, file, func, line, "error reading from file", path, 1);
+ clar__assert_equal(file, func, line, "mismatched file length", 1, "%"PRIuZ,
(size_t)expected_bytes, (size_t)total_bytes);
}
#include "clar.h"
#include <git2.h>
-#include <posix.h>
#include "common.h"
+#include "posix.h"
/**
* Replace for `clar_must_pass` that passes the last library error as the
*
* Use this wrapper around all `git_` library calls that return error codes!
*/
-#define cl_git_pass(expr) cl_git_expect((expr), 0, __FILE__, __LINE__)
+#define cl_git_pass(expr) cl_git_expect((expr), 0, __FILE__, __func__, __LINE__)
-#define cl_git_fail_with(error, expr) cl_git_expect((expr), error, __FILE__, __LINE__)
+#define cl_git_fail_with(error, expr) cl_git_expect((expr), error, __FILE__, __func__, __LINE__)
-#define cl_git_expect(expr, expected, file, line) do { \
+#define cl_git_expect(expr, expected, file, func, line) do { \
int _lg2_error; \
git_error_clear(); \
if ((_lg2_error = (expr)) != expected) \
- cl_git_report_failure(_lg2_error, expected, file, line, "Function call failed: " #expr); \
+ cl_git_report_failure(_lg2_error, expected, file, func, line, "Function call failed: " #expr); \
} while (0)
/**
#define cl_git_fail(expr) do { \
if ((expr) == 0) \
git_error_clear(), \
- cl_git_report_failure(0, 0, __FILE__, __LINE__, "Function call succeeded: " #expr); \
+ cl_git_report_failure(0, 0, __FILE__, __func__, __LINE__, "Function call succeeded: " #expr); \
} while (0)
/**
int _win32_res; \
if ((_win32_res = (expr)) == 0) { \
git_error_set(GIT_ERROR_OS, "Returned: %d, system error code: %lu", _win32_res, GetLastError()); \
- cl_git_report_failure(_win32_res, 0, __FILE__, __LINE__, "System call failed: " #expr); \
+ cl_git_report_failure(_win32_res, 0, __FILE__, __func__, __LINE__, "System call failed: " #expr); \
} \
} while(0)
typedef struct {
int error;
const char *file;
+ const char *func;
int line;
const char *expr;
char error_msg[4096];
} cl_git_thread_err;
#ifdef GIT_THREADS
-# define cl_git_thread_pass(threaderr, expr) cl_git_thread_pass_(threaderr, (expr), __FILE__, __LINE__)
+# define cl_git_thread_pass(threaderr, expr) cl_git_thread_pass_(threaderr, (expr), __FILE__, __func__, __LINE__)
#else
# define cl_git_thread_pass(threaderr, expr) cl_git_pass(expr)
#endif
-#define cl_git_thread_pass_(__threaderr, __expr, __file, __line) do { \
+#define cl_git_thread_pass_(__threaderr, __expr, __file, __func, __line) do { \
git_error_clear(); \
if ((((cl_git_thread_err *)__threaderr)->error = (__expr)) != 0) { \
const git_error *_last = git_error_last(); \
((cl_git_thread_err *)__threaderr)->file = __file; \
+ ((cl_git_thread_err *)__threaderr)->func = __func; \
((cl_git_thread_err *)__threaderr)->line = __line; \
((cl_git_thread_err *)__threaderr)->expr = "Function call failed: " #__expr; \
p_snprintf(((cl_git_thread_err *)__threaderr)->error_msg, 4096, "thread 0x%" PRIxZ " - error %d - %s", \
{
cl_git_thread_err *threaderr = (cl_git_thread_err *)data;
if (threaderr->error != 0)
- clar__assert(0, threaderr->file, threaderr->line, threaderr->expr, threaderr->error_msg, 1);
+ clar__assert(0, threaderr->file, threaderr->func, threaderr->line, threaderr->expr, threaderr->error_msg, 1);
}
-void cl_git_report_failure(int, int, const char *, int, const char *);
+void cl_git_report_failure(int, int, const char *, const char *, int, const char *);
-#define cl_assert_at_line(expr,file,line) \
- clar__assert((expr) != 0, file, line, "Expression is not true: " #expr, NULL, 1)
+#define cl_assert_at_line(expr,file,func,line) \
+ clar__assert((expr) != 0, file, func, line, "Expression is not true: " #expr, NULL, 1)
GIT_INLINE(void) clar__assert_in_range(
int lo, int val, int hi,
- const char *file, int line, const char *err, int should_abort)
+ const char *file, const char *func, int line,
+ const char *err, int should_abort)
{
if (lo > val || hi < val) {
char buf[128];
p_snprintf(buf, sizeof(buf), "%d not in [%d,%d]", val, lo, hi);
- clar__fail(file, line, err, buf, should_abort);
+ clar__fail(file, func, line, err, buf, should_abort);
}
}
#define cl_assert_equal_sz(sz1,sz2) do { \
size_t __sz1 = (size_t)(sz1), __sz2 = (size_t)(sz2); \
- clar__assert_equal(__FILE__,__LINE__,#sz1 " != " #sz2, 1, "%"PRIuZ, __sz1, __sz2); \
+ clar__assert_equal(__FILE__,__func__,__LINE__,#sz1 " != " #sz2, 1, "%"PRIuZ, __sz1, __sz2); \
} while (0)
#define cl_assert_in_range(L,V,H) \
- clar__assert_in_range((L),(V),(H),__FILE__,__LINE__,"Range check: " #V " in [" #L "," #H "]", 1)
+ clar__assert_in_range((L),(V),(H),__FILE__,__func__,__LINE__,"Range check: " #V " in [" #L "," #H "]", 1)
#define cl_assert_equal_file(DATA,SIZE,PATH) \
- clar__assert_equal_file(DATA,SIZE,0,PATH,__FILE__,(int)__LINE__)
+ clar__assert_equal_file(DATA,SIZE,0,PATH,__FILE__,__func__,(int)__LINE__)
#define cl_assert_equal_file_ignore_cr(DATA,SIZE,PATH) \
- clar__assert_equal_file(DATA,SIZE,1,PATH,__FILE__,(int)__LINE__)
+ clar__assert_equal_file(DATA,SIZE,1,PATH,__FILE__,__func__,(int)__LINE__)
void clar__assert_equal_file(
const char *expected_data,
int ignore_cr,
const char *path,
const char *file,
+ const char *func,
int line);
GIT_INLINE(void) clar__assert_equal_oid(
- const char *file, int line, const char *desc,
+ const char *file, const char *func, int line, const char *desc,
const git_oid *one, const git_oid *two)
{
if (git_oid_cmp(one, two)) {
git_oid_fmt(&err[1], one);
git_oid_fmt(&err[47], two);
- clar__fail(file, line, desc, err, 1);
+ clar__fail(file, func, line, desc, err, 1);
}
}
#define cl_assert_equal_oid(one, two) \
- clar__assert_equal_oid(__FILE__, __LINE__, \
+ clar__assert_equal_oid(__FILE__, __func__, __LINE__, \
"OID mismatch: " #one " != " #two, (one), (two))
/*
void cl_sandbox_set_search_path_defaults(void);
+#ifdef GIT_WIN32
+# define cl_msleep(x) Sleep(x)
+#else
+# define cl_msleep(x) usleep(1000 * (x))
+#endif
+
#ifdef GIT_WIN32
bool cl_sandbox_supports_8dot3(void);
#endif
-#include "clar_libgit2.h"
#include "clar_libgit2_trace.h"
+#include "clar_libgit2.h"
#include "clar_libgit2_timer.h"
#include "trace.h"
-
struct method {
const char *name;
void (*git_trace_cb)(git_trace_level_t level, const char *msg);
void (*close)(void);
};
+static const char *message_prefix(git_trace_level_t level)
+{
+ switch (level) {
+ case GIT_TRACE_NONE:
+ return "[NONE]: ";
+ case GIT_TRACE_FATAL:
+ return "[FATAL]: ";
+ case GIT_TRACE_ERROR:
+ return "[ERROR]: ";
+ case GIT_TRACE_WARN:
+ return "[WARN]: ";
+ case GIT_TRACE_INFO:
+ return "[INFO]: ";
+ case GIT_TRACE_DEBUG:
+ return "[DEBUG]: ";
+ case GIT_TRACE_TRACE:
+ return "[TRACE]: ";
+ default:
+ return "[?????]: ";
+ }
+}
-#if defined(GIT_TRACE)
static void _git_trace_cb__printf(git_trace_level_t level, const char *msg)
{
- /* TODO Use level to print a per-message prefix. */
- GIT_UNUSED(level);
-
- printf("%s\n", msg);
+ printf("%s%s\n", message_prefix(level), msg);
}
#if defined(GIT_WIN32)
static void _git_trace_cb__debug(git_trace_level_t level, const char *msg)
{
- /* TODO Use level to print a per-message prefix. */
- GIT_UNUSED(level);
-
+ OutputDebugString(message_prefix(level));
OutputDebugString(msg);
OutputDebugString("\n");
- printf("%s\n", msg);
+ printf("%s%s\n", message_prefix(level), msg);
}
#else
#define _git_trace_cb__debug _git_trace_cb__printf
static int s_trace_loaded = 0;
static int s_trace_level = GIT_TRACE_NONE;
static struct method *s_trace_method = NULL;
-
+static int s_trace_tests = 0;
static int set_method(const char *name)
{
{
char *sz_level;
char *sz_method;
+ char *sz_tests;
s_trace_loaded = 1;
sz_method = cl_getenv("CLAR_TRACE_METHOD");
if (set_method(sz_method) < 0)
set_method(NULL);
+
+ sz_tests = cl_getenv("CLAR_TRACE_TESTS");
+ if (sz_tests != NULL)
+ s_trace_tests = 1;
}
#define HR "================================================================"
{
GIT_UNUSED(payload);
+ if (!s_trace_tests)
+ return;
+
switch (ev) {
case CL_TRACE__SUITE_BEGIN:
git_trace(GIT_TRACE_TRACE, "\n\n%s\n%s: Begin Suite", HR, suite_name);
}
}
-#endif /*GIT_TRACE*/
-
/**
* Setup/Enable git_trace() based upon settings user's environment.
- *
*/
void cl_global_trace_register(void)
{
-#if defined(GIT_TRACE)
if (!s_trace_loaded)
_load_trace_params();
git_trace_set(s_trace_level, s_trace_method->git_trace_cb);
cl_trace_register(_cl_trace_cb__event_handler, NULL);
-#endif
}
/**
*/
void cl_global_trace_disable(void)
{
-#if defined(GIT_TRACE)
cl_trace_register(NULL, NULL);
git_trace_set(GIT_TRACE_NONE, NULL);
if (s_trace_method && s_trace_method->close)
* since we only want to hit the environment variables
* once.
*/
-#endif
}
#include "git2/clone.h"
#include "repository.h"
+#include "repo/repo_helpers.h"
static git_clone_options g_options;
static git_repository *g_repo;
void test_clone_empty__cleanup(void)
{
+ cl_fixture_cleanup("tmp_global_path");
cl_git_sandbox_cleanup();
}
expected_tracked_branch_name));
}
+void test_clone_empty__respects_initialbranch_config(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+
+ create_tmp_global_config("tmp_global_path", "init.defaultbranch", "my_default_branch");
+
+ cl_set_cleanup(&cleanup_repository, "./empty");
+
+ g_options.bare = true;
+ cl_git_pass(git_clone(&g_repo_cloned, "./empty_bare.git", "./empty", &g_options));
+ cl_git_pass(git_branch_upstream_name(&buf, g_repo_cloned, "refs/heads/my_default_branch"));
+ cl_assert_equal_s("refs/remotes/origin/my_default_branch", buf.ptr);
+ git_buf_dispose(&buf);
+}
+
void test_clone_empty__can_clone_an_empty_local_repo(void)
{
cl_set_cleanup(&cleanup_repository, "./empty");
#include "buffer.h"
#include "path.h"
#include "posix.h"
-#include "fileops.h"
+#include "futils.h"
static int file_url(git_buf *buf, const char *host, const char *path)
{
#include "clar_libgit2.h"
#include "git2/clone.h"
-#include "git2/sys/commit.h"
#include "../submodule/submodule_helpers.h"
#include "remote.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
#define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository"
}
static int clone_cancel_fetch_transfer_progress_cb(
- const git_transfer_progress *stats, void *data)
+ const git_indexer_progress *stats, void *data)
{
GIT_UNUSED(stats); GIT_UNUSED(data);
return -54321;
git_repository_free(repo);
cl_fixture_cleanup("./repowithunborn");
}
-
-static int just_return_origin(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
-{
- GIT_UNUSED(url); GIT_UNUSED(payload);
-
- return git_remote_lookup(out, repo, name);
-}
-
-static int just_return_repo(git_repository **out, const char *path, int bare, void *payload)
-{
- git_submodule *sm = payload;
-
- GIT_UNUSED(path); GIT_UNUSED(bare);
-
- return git_submodule_open(out, sm);
-}
-
-void test_clone_nonetwork__clone_submodule(void)
-{
- git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
- git_index *index;
- git_oid tree_id, commit_id;
- git_submodule *sm;
- git_signature *sig;
- git_repository *sm_repo;
-
- cl_git_pass(git_repository_init(&g_repo, "willaddsubmodule", false));
-
-
- /* Create the submodule structure, clone into it and finalize */
- cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "testrepo", true));
-
- clone_opts.repository_cb = just_return_repo;
- clone_opts.repository_cb_payload = sm;
- clone_opts.remote_cb = just_return_origin;
- clone_opts.remote_cb_payload = sm;
- cl_git_pass(git_clone(&sm_repo, cl_fixture("testrepo.git"), "testrepo", &clone_opts));
- cl_git_pass(git_submodule_add_finalize(sm));
- git_repository_free(sm_repo);
- git_submodule_free(sm);
-
- cl_git_pass(git_repository_index(&index, g_repo));
- cl_git_pass(git_index_write_tree(&tree_id, index));
- git_index_free(index);
-
- cl_git_pass(git_signature_now(&sig, "Submoduler", "submoduler@local"));
- cl_git_pass(git_commit_create_from_ids(&commit_id, g_repo, "HEAD", sig, sig, NULL, "A submodule\n",
- &tree_id, 0, NULL));
-
- git_signature_free(sig);
-
- assert_submodule_exists(g_repo, "testrepo");
-}
#include "git2/clone.h"
#include "git2/transport.h"
#include "git2/sys/transport.h"
-#include "fileops.h"
+#include "futils.h"
static int custom_transport(
git_transport **out,
cl_git_fail(create_commit_from_ids(&commit_id, &tree_id, &parent_id));
}
-void test_commit_write__attach_singleline_signature(void)
+void test_commit_write__attach_signature_checks_objects(void)
{
const char *sig = "magic word: pretty please";
+ const char *badtree = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
+parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+\n\
+a simple commit which does not work\n";
- const char *data = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
+ const char *badparent = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
\n\
+a simple commit which does not work\n";
+
+ git_oid id;
+
+ cl_git_fail_with(-1, git_commit_create_with_signature(&id, g_repo, badtree, sig, "magicsig"));
+ cl_git_fail_with(-1, git_commit_create_with_signature(&id, g_repo, badparent, sig, "magicsig"));
+
+}
+
+void test_commit_write__attach_singleline_signature(void)
+{
+ const char *sig = "magic word: pretty please";
+
+ const char *data = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
+author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
+\n\
a simple commit which works\n";
- const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
-parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+ const char *complete = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
magicsig magic word: pretty please\n\
=ozeK\n\
-----END PGP SIGNATURE-----";
- const char *data = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
-parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+ const char *data = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
\n\
a simple commit which works\n";
-const char *complete = "tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6\n\
-parent 34734e478d6cf50c27c9d69026d93974d052c454\n\
+const char *complete = "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n\
+parent 8496071c1b46c854b31185ea97743be6a8774479\n\
author Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800\n\
gpgsig -----BEGIN PGP SIGNATURE-----\n\
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
+#include "repository.h"
#ifdef GIT_WIN32
# define ROOT_PREFIX "C:"
static void assert_condition_includes(const char *keyword, const char *path, bool expected)
{
- git_config *cfg;
git_buf buf = GIT_BUF_INIT;
+ git_config *cfg;
- git_buf_printf(&buf, "[includeIf \"%s:%s\"]\n", keyword, path);
- git_buf_puts(&buf, "path = other\n");
+ cl_git_pass(git_buf_printf(&buf, "[includeIf \"%s:%s\"]\n", keyword, path));
+ cl_git_pass(git_buf_puts(&buf, "path = other\n"));
cl_git_mkfile("empty_standard_repo/.git/config", buf.ptr);
cl_git_mkfile("empty_standard_repo/.git/other", "[foo]\nbar=baz\n");
git_config_free(cfg);
}
+static char *sandbox_path(git_buf *buf, const char *suffix)
+{
+ char *path = p_realpath(clar_sandbox_path(), NULL);
+ cl_assert(path);
+ cl_git_pass(git_buf_attach(buf, path, 0));
+ cl_git_pass(git_buf_joinpath(buf, buf->ptr, suffix));
+ return buf->ptr;
+}
+
void test_config_conditionals__gitdir(void)
{
git_buf path = GIT_BUF_INIT;
- char *sandbox_path;
assert_condition_includes("gitdir", ROOT_PREFIX "/", true);
- assert_condition_includes("gitdir", "empty_standard_repo", true);
+ assert_condition_includes("gitdir", "empty_stand", false);
+ assert_condition_includes("gitdir", "empty_stand/", false);
+ assert_condition_includes("gitdir", "empty_stand/.git", false);
+ assert_condition_includes("gitdir", "empty_stand/.git/", false);
+ assert_condition_includes("gitdir", "empty_stand*/", true);
+ assert_condition_includes("gitdir", "empty_stand*/.git", true);
+ assert_condition_includes("gitdir", "empty_stand*/.git/", false);
+ assert_condition_includes("gitdir", "empty_standard_repo", false);
assert_condition_includes("gitdir", "empty_standard_repo/", true);
- assert_condition_includes("gitdir", "./", true);
+ assert_condition_includes("gitdir", "empty_standard_repo/.git", true);
+ assert_condition_includes("gitdir", "empty_standard_repo/.git/", false);
+
+ assert_condition_includes("gitdir", "./", false);
assert_condition_includes("gitdir", ROOT_PREFIX "/nonexistent", false);
assert_condition_includes("gitdir", ROOT_PREFIX "/empty_standard_repo", false);
- assert_condition_includes("gitdir", "empty_stand", false);
assert_condition_includes("gitdir", "~/empty_standard_repo", false);
- sandbox_path = p_realpath(clar_sandbox_path(), NULL);
-
- git_buf_joinpath(&path, sandbox_path, "/");
- assert_condition_includes("gitdir", path.ptr, true);
-
- git_buf_joinpath(&path, sandbox_path, "/*");
- assert_condition_includes("gitdir", path.ptr, true);
+ assert_condition_includes("gitdir", sandbox_path(&path, "/"), true);
+ assert_condition_includes("gitdir", sandbox_path(&path, "/*"), false);
+ assert_condition_includes("gitdir", sandbox_path(&path, "/**"), true);
- git_buf_joinpath(&path, sandbox_path, "empty_standard_repo");
- assert_condition_includes("gitdir", path.ptr, true);
+ assert_condition_includes("gitdir", sandbox_path(&path, "empty_standard_repo"), false);
+ assert_condition_includes("gitdir", sandbox_path(&path, "empty_standard_repo/"), true);
+ assert_condition_includes("gitdir", sandbox_path(&path, "empty_standard_repo/"), true);
+ assert_condition_includes("gitdir", sandbox_path(&path, "Empty_Standard_Repo"), false);
+ assert_condition_includes("gitdir", sandbox_path(&path, "Empty_Standard_Repo/"), false);
- git_buf_joinpath(&path, sandbox_path, "Empty_Standard_Repo");
- assert_condition_includes("gitdir", path.ptr, false);
-
- git__free(sandbox_path);
git_buf_dispose(&path);
}
void test_config_conditionals__gitdir_i(void)
{
git_buf path = GIT_BUF_INIT;
- char *sandbox_path;
-
- sandbox_path = p_realpath(clar_sandbox_path(), NULL);
-
- git_buf_joinpath(&path, sandbox_path, "empty_standard_repo");
- assert_condition_includes("gitdir/i", path.ptr, true);
- git_buf_joinpath(&path, sandbox_path, "EMPTY_STANDARD_REPO");
- assert_condition_includes("gitdir/i", path.ptr, true);
+ assert_condition_includes("gitdir/i", sandbox_path(&path, "empty_standard_repo/"), true);
+ assert_condition_includes("gitdir/i", sandbox_path(&path, "EMPTY_STANDARD_REPO/"), true);
- git__free(sandbox_path);
git_buf_dispose(&path);
}
{
assert_condition_includes("foobar", ".git", false);
}
+
+static void set_head(git_repository *repo, const char *name)
+{
+ cl_git_pass(git_repository_create_head(git_repository_path(repo), name));
+}
+
+void test_config_conditionals__onbranch(void)
+{
+ assert_condition_includes("onbranch", "master", true);
+ assert_condition_includes("onbranch", "m*", true);
+ assert_condition_includes("onbranch", "*", true);
+ assert_condition_includes("onbranch", "master/", false);
+ assert_condition_includes("onbranch", "foo", false);
+
+ set_head(_repo, "foo");
+ assert_condition_includes("onbranch", "master", false);
+ assert_condition_includes("onbranch", "foo", true);
+ assert_condition_includes("onbranch", "f*o", true);
+
+ set_head(_repo, "dir/ref");
+ assert_condition_includes("onbranch", "dir/ref", true);
+ assert_condition_includes("onbranch", "dir/", true);
+ assert_condition_includes("onbranch", "dir/*", true);
+ assert_condition_includes("onbranch", "dir/**", true);
+ assert_condition_includes("onbranch", "**", true);
+ assert_condition_includes("onbranch", "dir", false);
+ assert_condition_includes("onbranch", "dir*", false);
+
+ set_head(_repo, "dir/subdir/ref");
+ assert_condition_includes("onbranch", "dir/subdir/", true);
+ assert_condition_includes("onbranch", "dir/subdir/*", true);
+ assert_condition_includes("onbranch", "dir/subdir/ref", true);
+ assert_condition_includes("onbranch", "dir/", true);
+ assert_condition_includes("onbranch", "dir/**", true);
+ assert_condition_includes("onbranch", "**", true);
+ assert_condition_includes("onbranch", "dir", false);
+ assert_condition_includes("onbranch", "dir*", false);
+ assert_condition_includes("onbranch", "dir/*", false);
+}
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
void test_config_global__initialize(void)
{
void test_config_global__cleanup(void)
{
cl_sandbox_set_search_path_defaults();
+ cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
+ cl_git_pass(git_futils_rmdir_r("xdg", NULL, GIT_RMDIR_REMOVE_FILES));
+ cl_git_pass(git_futils_rmdir_r("etc", NULL, GIT_RMDIR_REMOVE_FILES));
}
void test_config_global__open_global(void)
{
git_config *cfg, *global, *selected, *dummy;
+ int32_t value;
+
+ cl_git_mkfile("home/.gitconfig", "[global]\n test = 4567\n");
cl_git_pass(git_config_open_default(&cfg));
+ cl_git_pass(git_config_get_int32(&value, cfg, "global.test"));
+ cl_assert_equal_i(4567, value);
+
cl_git_pass(git_config_open_level(&global, cfg, GIT_CONFIG_LEVEL_GLOBAL));
+ cl_git_pass(git_config_get_int32(&value, global, "global.test"));
+ cl_assert_equal_i(4567, value);
+
cl_git_fail(git_config_open_level(&dummy, cfg, GIT_CONFIG_LEVEL_XDG));
+
cl_git_pass(git_config_open_global(&selected, cfg));
+ cl_git_pass(git_config_get_int32(&value, selected, "global.test"));
+ cl_assert_equal_i(4567, value);
git_config_free(selected);
git_config_free(global);
git_config_free(cfg);
}
+void test_config_global__open_symlinked_global(void)
+{
+#ifndef GIT_WIN32
+ git_config *cfg;
+ int32_t value;
+
+ cl_git_mkfile("home/.gitconfig.linked", "[global]\n test = 4567\n");
+ cl_must_pass(symlink(".gitconfig.linked", "home/.gitconfig"));
+
+ cl_git_pass(git_config_open_default(&cfg));
+ cl_git_pass(git_config_get_int32(&value, cfg, "global.test"));
+ cl_assert_equal_i(4567, value);
+
+ git_config_free(cfg);
+#endif
+}
+
void test_config_global__lock_missing_global_config(void)
{
git_config *cfg;
git_config_entry *entry;
git_transaction *transaction;
- p_unlink("home/.gitconfig"); /* No global config */
+ (void)p_unlink("home/.gitconfig"); /* No global config */
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_lock(&transaction, cfg));
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
static git_config *cfg;
static git_buf buf;
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("included"));
}
+
+void test_config_include__variables_in_included_override_including(void)
+{
+ int i;
+
+ cl_git_mkfile("top-level", "[foo]\nbar = 1\n[include]\npath = included");
+ cl_git_mkfile("included", "[foo]\nbar = 2");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+ cl_git_pass(git_config_get_int32(&i, cfg, "foo.bar"));
+ cl_assert_equal_i(i, 2);
+
+ cl_git_pass(p_unlink("top-level"));
+ cl_git_pass(p_unlink("included"));
+}
+
+void test_config_include__variables_in_including_override_included(void)
+{
+ int i;
+
+ cl_git_mkfile("top-level", "[include]\npath = included\n[foo]\nbar = 1");
+ cl_git_mkfile("included", "[foo]\nbar = 2");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
+ cl_git_pass(git_config_get_int32(&i, cfg, "foo.bar"));
+ cl_assert_equal_i(i, 1);
+
+ cl_git_pass(p_unlink("top-level"));
+ cl_git_pass(p_unlink("included"));
+}
#include "clar_libgit2.h"
#include "filebuf.h"
-#include "fileops.h"
+#include "futils.h"
#include "posix.h"
#define TEST_CONFIG "git-new-config"
git_buf_dispose(&buf);
git_config_free(config);
- p_unlink(TEST_CONFIG);
+ cl_must_pass(p_unlink(TEST_CONFIG));
}
git_buf_dispose(&buf);
}
+void test_config_read__arbitrary_whitespace_before_subsection(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+ git_config *cfg;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "[some \t \"subsection\"]\n var = value\n");
+ cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
+ cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.subsection.var"));
+ cl_assert_equal_s(buf.ptr, "value");
+
+ git_config_free(cfg);
+ git_buf_dispose(&buf);
+}
+
+void test_config_read__no_whitespace_after_subsection(void)
+{
+ git_config *cfg;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "[some \"subsection\" ]\n var = value\n");
+ cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+ git_config_free(cfg);
+}
+
+void test_config_read__invalid_space_section(void)
+{
+ git_config *cfg;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some section]\n var = value\n");
+ cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+ git_config_free(cfg);
+}
+
+void test_config_read__invalid_quoted_first_section(void)
+{
+ git_config *cfg;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[\"some\"]\n var = value\n");
+ cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+ git_config_free(cfg);
+}
+
+void test_config_read__invalid_unquoted_subsection(void)
+{
+ git_config *cfg;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some sub section]\n var = value\n");
+ cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+ git_config_free(cfg);
+}
+
+void test_config_read__invalid_quoted_third_section(void)
+{
+ git_config *cfg;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some sub \"section\"]\n var = value\n");
+ cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
+
+ git_config_free(cfg);
+}
+
+void test_config_read__unreadable_file_ignored(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+ git_config *cfg;
+ int ret;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "[some] var = value\n[some \"OtheR\"] var = value");
+ cl_git_pass(p_chmod("./testconfig", 0));
+
+ ret = git_config_open_ondisk(&cfg, "./test/config");
+ cl_assert(ret == 0 || ret == GIT_ENOTFOUND);
+
+ git_config_free(cfg);
+ git_buf_dispose(&buf);
+}
+
void test_config_read__single_line(void)
{
git_buf buf = GIT_BUF_INIT;
git_buf_dispose(&buf);
git_config_free(cfg);
}
+
+enum {
+ MAP_TRUE = 0,
+ MAP_FALSE = 1,
+ MAP_ALWAYS = 2
+};
+
+static git_configmap _test_map1[] = {
+ {GIT_CONFIGMAP_STRING, "always", MAP_ALWAYS},
+ {GIT_CONFIGMAP_FALSE, NULL, MAP_FALSE},
+ {GIT_CONFIGMAP_TRUE, NULL, MAP_TRUE},
+};
+
+static git_configmap _test_map2[] = {
+ {GIT_CONFIGMAP_INT32, NULL, 0},
+};
+
+void test_config_read__get_mapped(void)
+{
+ git_config *cfg;
+ int val;
+ int known_good;
+
+ cl_set_cleanup(&clean_test_config, NULL);
+ cl_git_mkfile("./testconfig", "[header]\n"
+ " key1 = 1\n"
+ " key2 = true\n"
+ " key3\n"
+ " key4 = always\n"
+ " key5 = false\n"
+ " key6 = 0\n"
+ " key7 = never\n"
+ " key8 = On\n"
+ " key9 = off\n");
+ cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
+
+ // check parsing bool and string
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_TRUE);
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key2", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_TRUE);
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key3", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_TRUE);
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key8", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_TRUE);
+
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key4", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_ALWAYS);
+
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key5", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_FALSE);
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key6", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_FALSE);
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key9", _test_map1, ARRAY_SIZE(_test_map1)));
+ cl_assert_equal_i(val, MAP_FALSE);
+
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key7", _test_map1, ARRAY_SIZE(_test_map1)));
+
+ // check parsing int values
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_pass(git_config_get_int32(&known_good, cfg, "header.key1"));
+ cl_assert_equal_i(val, known_good);
+ cl_git_pass(git_config_get_mapped(&val, cfg, "header.key6", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_pass(git_config_get_int32(&known_good, cfg, "header.key6"));
+ cl_assert_equal_i(val, known_good);
+
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key2", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key3", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key4", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key5", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key7", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key8", _test_map2, ARRAY_SIZE(_test_map2)));
+ cl_git_fail(git_config_get_mapped(&val, cfg, "header.key9", _test_map2, ARRAY_SIZE(_test_map2)));
+
+ git_config_free(cfg);
+}
#include "clar_libgit2.h"
-void test_config_snapshot__create_snapshot(void)
-{
- int32_t tmp;
- git_config *cfg, *snapshot, *new_snapshot;
- const char *filename = "config-ext-change";
+#include "config_backend.h"
- cl_git_mkfile(filename, "[old]\nvalue = 5\n");
+static git_config *cfg;
+static git_config *snapshot;
- cl_git_pass(git_config_open_ondisk(&cfg, filename));
+void test_config_snapshot__cleanup(void)
+{
+ git_config_free(cfg);
+ cfg = NULL;
+ git_config_free(snapshot);
+ snapshot = NULL;
+}
- cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
- cl_assert_equal_i(5, tmp);
+void test_config_snapshot__create_snapshot(void)
+{
+ int32_t i;
+
+ cl_git_mkfile("config", "[old]\nvalue = 5\n");
+ cl_git_pass(git_config_open_ondisk(&cfg, "config"));
+ cl_git_pass(git_config_get_int32(&i, cfg, "old.value"));
+ cl_assert_equal_i(5, i);
cl_git_pass(git_config_snapshot(&snapshot, cfg));
/* Change the value on the file itself (simulate external process) */
- cl_git_mkfile(filename, "[old]\nvalue = 56\n");
-
- cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
- cl_assert_equal_i(56, tmp);
+ cl_git_mkfile("config", "[old]\nvalue = 56\n");
- cl_git_pass(git_config_get_int32(&tmp, snapshot, "old.value"));
- cl_assert_equal_i(5, tmp);
+ cl_git_pass(git_config_get_int32(&i, cfg, "old.value"));
+ cl_assert_equal_i(56, i);
+ cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
+ cl_assert_equal_i(5, i);
/* Change the value on the file itself (simulate external process) */
- cl_git_mkfile(filename, "[old]\nvalue = 999\n");
+ cl_git_mkfile("config", "[old]\nvalue = 999\n");
- cl_git_pass(git_config_snapshot(&new_snapshot, cfg));
+ /* Old snapshot should still have the old value */
+ cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
+ cl_assert_equal_i(5, i);
/* New snapshot should see new value */
- cl_git_pass(git_config_get_int32(&tmp, new_snapshot, "old.value"));
- cl_assert_equal_i(999, tmp);
-
- /* Old snapshot should still have the old value */
- cl_git_pass(git_config_get_int32(&tmp, snapshot, "old.value"));
- cl_assert_equal_i(5, tmp);
-
- git_config_free(new_snapshot);
git_config_free(snapshot);
- git_config_free(cfg);
+ cl_git_pass(git_config_snapshot(&snapshot, cfg));
+ cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
+ cl_assert_equal_i(999, i);
+
+ cl_git_pass(p_unlink("config"));
}
static int count_me(const git_config_entry *entry, void *payload)
void test_config_snapshot__multivar(void)
{
- int count = 0;
- git_config *cfg, *snapshot;
- const char *filename = "config-file";
+ int count;
- cl_git_mkfile(filename, "[old]\nvalue = 5\nvalue = 6\n");
-
- cl_git_pass(git_config_open_ondisk(&cfg, filename));
+ count = 0;
+ cl_git_mkfile("config", "[old]\nvalue = 5\nvalue = 6\n");
+ cl_git_pass(git_config_open_ondisk(&cfg, "config"));
cl_git_pass(git_config_get_multivar_foreach(cfg, "old.value", NULL, count_me, &count));
+ cl_assert_equal_i(2, count);
+ count = 0;
+ cl_git_pass(git_config_snapshot(&snapshot, cfg));
+ cl_git_pass(git_config_get_multivar_foreach(snapshot, "old.value", NULL, count_me, &count));
cl_assert_equal_i(2, count);
+ cl_git_pass(p_unlink("config"));
+}
+
+void test_config_snapshot__includes(void)
+{
+ int i;
+
+ cl_git_mkfile("including", "[include]\npath = included");
+ cl_git_mkfile("included", "[section]\nkey = 1\n");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_git_pass(git_config_snapshot(&snapshot, cfg));
- git_config_free(cfg);
- count = 0;
- cl_git_pass(git_config_get_multivar_foreach(snapshot, "old.value", NULL, count_me, &count));
+ cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
+ cl_assert_equal_i(i, 1);
- cl_assert_equal_i(2, count);
+ /* Rewrite "included" config */
+ cl_git_mkfile("included", "[section]\nkey = 11\n");
- git_config_free(snapshot);
+ /* Assert that the live config changed, but snapshot remained the same */
+ cl_git_pass(git_config_get_int32(&i, cfg, "section.key"));
+ cl_assert_equal_i(i, 11);
+ cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
+ cl_assert_equal_i(i, 1);
+
+ cl_git_pass(p_unlink("including"));
+ cl_git_pass(p_unlink("included"));
+}
+
+void test_config_snapshot__snapshot(void)
+{
+ git_config *snapshot_snapshot;
+ int i;
+
+ cl_git_mkfile("configfile", "[section]\nkey = 1\n");
+
+ cl_git_pass(git_config_open_ondisk(&cfg, "configfile"));
+ cl_git_pass(git_config_snapshot(&snapshot, cfg));
+
+ cl_git_pass(git_config_snapshot(&snapshot_snapshot, snapshot));
+
+ cl_git_pass(git_config_get_int32(&i, snapshot_snapshot, "section.key"));
+ cl_assert_equal_i(i, 1);
+
+ git_config_free(snapshot_snapshot);
+
+ cl_git_pass(p_unlink("configfile"));
+}
+
+void test_config_snapshot__snapshot_from_in_memony(void)
+{
+ const char *configuration = "[section]\nkey = 1\n";
+ git_config_backend *backend;
+ int i;
+
+ cl_git_pass(git_config_new(&cfg));
+ cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration)));
+ cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0));
+
+ cl_git_pass(git_config_snapshot(&snapshot, cfg));
+ cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
+ cl_assert_equal_i(i, 1);
}
#include "clar_libgit2.h"
#include "filebuf.h"
-#include "fileops.h"
+#include "futils.h"
#include "posix.h"
#define TEST_CONFIG "git-test-config"
assert_config_value(config, "some.section.multi", "hi, this is a ; multiline comment # with ;\n special chars and other stuff !@#");
assert_config_value(config, "some.section.multi2", "good, this is a ; multiline comment # with ;\n special chars and other stuff !@#");
assert_config_value(config, "some.section.back", "this is \ba phrase");
+ assert_config_value(config, "some.section.dollar", "some $sign");
+ assert_config_value(config, "some.section.multiquotes", "!ls x ls # comment2 $HOME");
+ assert_config_value(config, "some.section.multiquotes2", "!ls x ls \"# comment2 $HOME\"");
+ assert_config_value(config, "some.section.multiquotes3", "hi # ho there are # more quotes");
+ assert_config_value(config, "some.section.quotecomment", "hi # ho there are # more");
git_config_free(config);
}
for (i = 0; i < 10; i++) {
int32_t val;
cl_git_pass(git_config_set_int32(config_w, key, i));
+ cl_msleep(1);
cl_git_pass(git_config_get_int32(&val, config_r, key));
cl_assert_equal_i(i, val);
}
git_config_free(config_r);
git_config_free(config_w);
}
+
+static int foreach_cb(const git_config_entry *entry, void *payload)
+{
+ if (!strcmp(entry->name, "key.value")) {
+ *(char **)payload = git__strdup(entry->value);
+ return 0;
+ }
+ return -1;
+}
+
+void test_config_stress__foreach_refreshes(void)
+{
+ git_config *config_w, *config_r;
+ char *value = NULL;
+
+ cl_git_pass(git_config_open_ondisk(&config_w, "./cfg"));
+ cl_git_pass(git_config_open_ondisk(&config_r, "./cfg"));
+
+ cl_git_pass(git_config_set_string(config_w, "key.value", "1"));
+ cl_git_pass(git_config_foreach_match(config_r, "key.value", foreach_cb, &value));
+
+ cl_assert_equal_s(value, "1");
+
+ git_config_free(config_r);
+ git_config_free(config_w);
+ git__free(value);
+}
+
+void test_config_stress__foreach_refreshes_snapshot(void)
+{
+ git_config *config, *snapshot;
+ char *value = NULL;
+
+ cl_git_pass(git_config_open_ondisk(&config, "./cfg"));
+
+ cl_git_pass(git_config_set_string(config, "key.value", "1"));
+ cl_git_pass(git_config_snapshot(&snapshot, config));
+ cl_git_pass(git_config_foreach_match(snapshot, "key.value", foreach_cb, &value));
+
+ cl_assert_equal_s(value, "1");
+
+ git_config_free(snapshot);
+ git_config_free(config);
+ git__free(value);
+}
+
+void test_config_stress__huge_section_with_many_values(void)
+{
+ git_config *config;
+
+ if (!cl_is_env_set("GITTEST_INVASIVE_SPEED"))
+ cl_skip();
+
+ /*
+ * The config file is structured in such a way that is
+ * has a section header that is approximately 500kb of
+ * size followed by 40k entries. While the resulting
+ * configuration file itself is roughly 650kb in size and
+ * thus considered to be rather small, in the past we'd
+ * balloon to more than 20GB of memory (20000x500kb)
+ * while parsing the file. It thus was a trivial way to
+ * cause an out-of-memory situation and thus cause denial
+ * of service, e.g. via gitmodules.
+ */
+ cl_git_pass(git_config_open_ondisk(&config, cl_fixture("config/config-oom")));
+
+ git_config_free(config);
+}
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/sys/config.h"
#include "config.h"
--- /dev/null
+#ifdef GIT_ASSERT_HARD
+# undef GIT_ASSERT_HARD
+#endif
+
+#define GIT_ASSERT_HARD 0
+
+#include "clar_libgit2.h"
+
+static const char *hello_world = "hello, world";
+static const char *fail = "FAIL";
+
+static int dummy_fn(const char *myarg)
+{
+ GIT_ASSERT_ARG(myarg);
+ GIT_ASSERT_ARG(myarg != hello_world);
+ return 0;
+}
+
+static const char *fn_returns_string(const char *myarg)
+{
+ GIT_ASSERT_ARG_WITH_RETVAL(myarg, fail);
+ GIT_ASSERT_ARG_WITH_RETVAL(myarg != hello_world, fail);
+
+ return myarg;
+}
+
+static int bad_math(void)
+{
+ GIT_ASSERT(1 + 1 == 3);
+ return 42;
+}
+
+static const char *bad_returns_string(void)
+{
+ GIT_ASSERT_WITH_RETVAL(1 + 1 == 3, NULL);
+ return hello_world;
+}
+
+void test_core_assert__argument(void)
+{
+ cl_git_fail(dummy_fn(NULL));
+ cl_assert(git_error_last());
+ cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
+ cl_assert_equal_s("invalid argument: 'myarg'", git_error_last()->message);
+
+ cl_git_fail(dummy_fn(hello_world));
+ cl_assert(git_error_last());
+ cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
+ cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message);
+
+ cl_git_pass(dummy_fn("foo"));
+}
+
+void test_core_assert__argument_with_non_int_return_type(void)
+{
+ const char *foo = "foo";
+
+ cl_assert_equal_p(fail, fn_returns_string(NULL));
+ cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
+ cl_assert_equal_s("invalid argument: 'myarg'", git_error_last()->message);
+
+ cl_assert_equal_p(fail, fn_returns_string(hello_world));
+ cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
+ cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message);
+
+ cl_assert_equal_p(foo, fn_returns_string(foo));
+}
+
+void test_core_assert__argument_with_void_return_type(void)
+{
+ const char *foo = "foo";
+
+ git_error_clear();
+ fn_returns_string(hello_world);
+ cl_assert_equal_i(GIT_ERROR_INVALID, git_error_last()->klass);
+ cl_assert_equal_s("invalid argument: 'myarg != hello_world'", git_error_last()->message);
+
+ git_error_clear();
+ cl_assert_equal_p(foo, fn_returns_string(foo));
+ cl_assert_equal_p(NULL, git_error_last());
+}
+
+void test_core_assert__internal(void)
+{
+ cl_git_fail(bad_math());
+ cl_assert(git_error_last());
+ cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass);
+ cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message);
+
+ cl_assert_equal_p(NULL, bad_returns_string());
+ cl_assert(git_error_last());
+ cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass);
+ cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message);
+}
#include "buffer.h"
#include "buf_text.h"
#include "git2/sys/hashsig.h"
-#include "fileops.h"
+#include "futils.h"
#define TESTSTR "Have you seen that? Have you seeeen that??"
const char *test_string = TESTSTR;
git_buf_puts(&tgt, data_b);
cl_assert(git_buf_oom(&tgt) == 0);
cl_assert_equal_s(expected_data, git_buf_cstr(&tgt));
- cl_assert(tgt.size == expected_size);
+ cl_assert_equal_i(tgt.size, expected_size);
if (expected_asize > 0)
- cl_assert(tgt.asize == expected_asize);
+ cl_assert_equal_i(tgt.asize, expected_asize);
git_buf_dispose(&tgt);
}
REP16("x") REP16("o"), 32, 40);
check_buf_append(test_4096, "", test_4096, 4096, 4104);
- check_buf_append(test_4096, test_4096, test_8192, 8192, 9240);
+ check_buf_append(test_4096, test_4096, test_8192, 8192, 8200);
/* check sequences of appends */
check_buf_append_abc("a", "b", "c",
cl_git_fail_with(GIT_EINVALID, git_buf_grow(&buf, 1024));
}
+
+void test_core_buffer__dont_hit_infinite_loop_when_resizing(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_puts(&buf, "foobar"));
+ /*
+ * We do not care whether this succeeds or fails, which
+ * would depend on platform-specific allocation
+ * semantics. We only want to know that the function
+ * actually returns.
+ */
+ (void)git_buf_try_grow(&buf, SIZE_MAX, true);
+
+ git_buf_dispose(&buf);
+}
+
+void test_core_buffer__avoid_printing_into_oom_buffer(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+
+ /* Emulate OOM situation with a previous allocation */
+ buf.asize = 8;
+ buf.ptr = git_buf__oom;
+
+ /*
+ * Print the same string again. As the buffer still has
+ * an `asize` of 8 due to the previous print,
+ * `ENSURE_SIZE` would not try to reallocate the array at
+ * all. As it didn't explicitly check for `git_buf__oom`
+ * in earlier versions, this would've resulted in it
+ * returning successfully and thus `git_buf_puts` would
+ * just print into the `git_buf__oom` array.
+ */
+ cl_git_fail(git_buf_puts(&buf, "foobar"));
+}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "path.h"
#include "posix.h"
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
typedef struct name_data {
int count; /* return count */
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "sysdir.h"
#include "path.h"
git_filebuf file = GIT_FILEBUF_INIT;
const char *dir = "linkdir", *source = "linkdir/link";
-#ifdef GIT_WIN32
- cl_skip();
-#endif
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ cl_skip();
cl_git_pass(p_mkdir(dir, 0777));
cl_git_pass(p_symlink("target", source));
git_filebuf file = GIT_FILEBUF_INIT;
git_buf source = GIT_BUF_INIT, target = GIT_BUF_INIT;
-#ifdef GIT_WIN32
- cl_skip();
-#endif
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ cl_skip();
cl_git_pass(git_buf_joinpath(&source, clar_sandbox_path(), "linkdir/link"));
cl_git_pass(git_buf_joinpath(&target, clar_sandbox_path(), "linkdir/target"));
git_filebuf file = GIT_FILEBUF_INIT;
const char *dir = "linkdir", *source = "linkdir/link";
-#ifdef GIT_WIN32
- cl_skip();
-#endif
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ cl_skip();
cl_git_pass(p_mkdir(dir, 0777));
/* Endless loop */
p_unlink(filename);
}
-static void _extend(git_off_t i64len)
+static void _extend(off64_t i64len)
{
struct stat st;
int error;
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
/* Fixture setup and teardown */
void test_core_futils__initialize(void)
#endif
}
+void test_core_futils__recursive_rmdir_keeps_symlink_targets(void)
+{
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ cl_skip();
+
+ cl_git_pass(git_futils_mkdir_r("a/b", 0777));
+ cl_git_pass(git_futils_mkdir_r("dir-target", 0777));
+ cl_git_mkfile("dir-target/file", "Contents");
+ cl_git_mkfile("file-target", "Contents");
+ cl_must_pass(p_symlink("dir-target", "a/symlink"));
+ cl_must_pass(p_symlink("file-target", "a/b/symlink"));
+
+ cl_git_pass(git_futils_rmdir_r("a", NULL, GIT_RMDIR_REMOVE_FILES));
+
+ cl_assert(git_path_exists("dir-target"));
+ cl_assert(git_path_exists("file-target"));
+
+ cl_must_pass(p_unlink("dir-target/file"));
+ cl_must_pass(p_rmdir("dir-target"));
+ cl_must_pass(p_unlink("file-target"));
+}
create_symlink_func pCreateSymbolicLink;
cl_assert(module = GetModuleHandle("kernel32"));
- cl_assert(pCreateSymbolicLink = (create_symlink_func)GetProcAddress(module, "CreateSymbolicLinkA"));
+ cl_assert(pCreateSymbolicLink = (create_symlink_func)(void *)GetProcAddress(module, "CreateSymbolicLinkA"));
cl_win32_pass(pCreateSymbolicLink(new, old, is_dir));
#endif
create_hardlink_func pCreateHardLink;
cl_assert(module = GetModuleHandle("kernel32"));
- cl_assert(pCreateHardLink = (create_hardlink_func)GetProcAddress(module, "CreateHardLinkA"));
+ cl_assert(pCreateHardLink = (create_hardlink_func)(void *)GetProcAddress(module, "CreateHardLinkA"));
cl_win32_pass(pCreateHardLink(new, old, 0));
#endif
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "path.h"
#include "posix.h"
git_futils_rmdir_r("r", NULL, GIT_RMDIR_EMPTY_HIERARCHY);
}
-#define check_mode(X,A) check_mode_at_line((X), (A), __FILE__, __LINE__)
+#define check_mode(X,A) check_mode_at_line((X), (A), __FILE__, __func__, __LINE__)
static void check_mode_at_line(
- mode_t expected, mode_t actual, const char *file, int line)
+ mode_t expected, mode_t actual,
+ const char *file, const char *func, int line)
{
/* FAT filesystems don't support exec bit, nor group/world bits */
if (!cl_is_chmod_supported()) {
}
clar__assert_equal(
- file, line, "expected_mode != actual_mode", 1,
+ file, func, line, "expected_mode != actual_mode", 1,
"%07o", (int)expected, (int)(actual & 0777));
}
#include "clar_libgit2.h"
#include "oidmap.h"
-typedef struct {
+static struct {
git_oid oid;
size_t extra;
-} oidmap_item;
+} test_oids[0x0FFF];
-#define NITEMS 0x0fff
+static git_oidmap *g_map;
-void test_core_oidmap__basic(void)
+void test_core_oidmap__initialize(void)
{
- git_oidmap *map;
- oidmap_item items[NITEMS];
uint32_t i, j;
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i) {
+ uint32_t segment = i / 8;
+ int modi = i - (segment * 8);
+
+ test_oids[i].extra = i;
- for (i = 0; i < NITEMS; ++i) {
- items[i].extra = i;
for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) {
- items[i].oid.id[j * 4 ] = (unsigned char)i;
- items[i].oid.id[j * 4 + 1] = (unsigned char)(i >> 8);
- items[i].oid.id[j * 4 + 2] = (unsigned char)(i >> 16);
- items[i].oid.id[j * 4 + 3] = (unsigned char)(i >> 24);
+ test_oids[i].oid.id[j * 4 ] = (unsigned char)modi;
+ test_oids[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8);
+ test_oids[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16);
+ test_oids[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24);
}
- }
-
- map = git_oidmap_alloc();
- cl_assert(map != NULL);
-
- for (i = 0; i < NITEMS; ++i) {
- size_t pos;
- int ret;
-
- pos = git_oidmap_lookup_index(map, &items[i].oid);
- cl_assert(!git_oidmap_valid_index(map, pos));
-
- pos = git_oidmap_put(map, &items[i].oid, &ret);
- cl_assert(ret != 0);
- git_oidmap_set_value_at(map, pos, &items[i]);
+ test_oids[i].oid.id[ 8] = (unsigned char)i;
+ test_oids[i].oid.id[ 9] = (unsigned char)(i >> 8);
+ test_oids[i].oid.id[10] = (unsigned char)(i >> 16);
+ test_oids[i].oid.id[11] = (unsigned char)(i >> 24);
}
+ cl_git_pass(git_oidmap_new(&g_map));
+}
- for (i = 0; i < NITEMS; ++i) {
- size_t pos;
+void test_core_oidmap__cleanup(void)
+{
+ git_oidmap_free(g_map);
+}
- pos = git_oidmap_lookup_index(map, &items[i].oid);
- cl_assert(git_oidmap_valid_index(map, pos));
+void test_core_oidmap__basic(void)
+{
+ size_t i;
- cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]);
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i) {
+ cl_assert(!git_oidmap_exists(g_map, &test_oids[i].oid));
+ cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i]));
}
- git_oidmap_free(map);
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i) {
+ cl_assert(git_oidmap_exists(g_map, &test_oids[i].oid));
+ cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[i].oid), &test_oids[i]);
+ }
}
void test_core_oidmap__hash_collision(void)
{
- git_oidmap *map;
- oidmap_item items[NITEMS];
- uint32_t i, j;
-
- for (i = 0; i < NITEMS; ++i) {
- uint32_t segment = i / 8;
- int modi = i - (segment * 8);
-
- items[i].extra = i;
+ size_t i;
- for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) {
- items[i].oid.id[j * 4 ] = (unsigned char)modi;
- items[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8);
- items[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16);
- items[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24);
- }
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i) {
+ cl_assert(!git_oidmap_exists(g_map, &test_oids[i].oid));
+ cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i]));
+ }
- items[i].oid.id[ 8] = (unsigned char)i;
- items[i].oid.id[ 9] = (unsigned char)(i >> 8);
- items[i].oid.id[10] = (unsigned char)(i >> 16);
- items[i].oid.id[11] = (unsigned char)(i >> 24);
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i) {
+ cl_assert(git_oidmap_exists(g_map, &test_oids[i].oid));
+ cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[i].oid), &test_oids[i]);
}
+}
- map = git_oidmap_alloc();
- cl_assert(map != NULL);
+void test_core_oidmap__get_succeeds_with_existing_keys(void)
+{
+ size_t i;
- for (i = 0; i < NITEMS; ++i) {
- size_t pos;
- int ret;
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i)
+ cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i]));
- pos = git_oidmap_lookup_index(map, &items[i].oid);
- cl_assert(!git_oidmap_valid_index(map, pos));
+ for (i = 0; i < ARRAY_SIZE(test_oids); ++i)
+ cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[i].oid), &test_oids[i]);
+}
- pos = git_oidmap_put(map, &items[i].oid, &ret);
- cl_assert(ret != 0);
+void test_core_oidmap__get_fails_with_nonexisting_key(void)
+{
+ size_t i;
- git_oidmap_set_value_at(map, pos, &items[i]);
- }
+ /* Do _not_ add last OID to verify that we cannot look it up */
+ for (i = 0; i < ARRAY_SIZE(test_oids) - 1; ++i)
+ cl_git_pass(git_oidmap_set(g_map, &test_oids[i].oid, &test_oids[i]));
+
+ cl_assert_equal_p(git_oidmap_get(g_map, &test_oids[ARRAY_SIZE(test_oids) - 1].oid), NULL);
+}
+void test_core_oidmap__setting_oid_persists(void)
+{
+ git_oid oids[] = {
+ {{ 0x01 }},
+ {{ 0x02 }},
+ {{ 0x03 }}
+ };
+
+ cl_git_pass(git_oidmap_set(g_map, &oids[0], "one"));
+ cl_git_pass(git_oidmap_set(g_map, &oids[1], "two"));
+ cl_git_pass(git_oidmap_set(g_map, &oids[2], "three"));
+
+ cl_assert_equal_s(git_oidmap_get(g_map, &oids[0]), "one");
+ cl_assert_equal_s(git_oidmap_get(g_map, &oids[1]), "two");
+ cl_assert_equal_s(git_oidmap_get(g_map, &oids[2]), "three");
+}
- for (i = 0; i < NITEMS; ++i) {
- size_t pos;
+void test_core_oidmap__setting_existing_key_updates(void)
+{
+ git_oid oids[] = {
+ {{ 0x01 }},
+ {{ 0x02 }},
+ {{ 0x03 }}
+ };
- pos = git_oidmap_lookup_index(map, &items[i].oid);
- cl_assert(git_oidmap_valid_index(map, pos));
+ cl_git_pass(git_oidmap_set(g_map, &oids[0], "one"));
+ cl_git_pass(git_oidmap_set(g_map, &oids[1], "two"));
+ cl_git_pass(git_oidmap_set(g_map, &oids[2], "three"));
+ cl_assert_equal_i(git_oidmap_size(g_map), 3);
- cl_assert_equal_p(git_oidmap_value_at(map, pos), &items[i]);
- }
+ cl_git_pass(git_oidmap_set(g_map, &oids[1], "other"));
+ cl_assert_equal_i(git_oidmap_size(g_map), 3);
- git_oidmap_free(map);
+ cl_assert_equal_s(git_oidmap_get(g_map, &oids[1]), "other");
}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
static void
check_dirname(const char *A, const char *B)
# endif
#endif
-#include <locale.h>
-
#include "clar_libgit2.h"
+#include "futils.h"
#include "posix.h"
-#include "userdiff.h"
void test_core_posix__initialize(void)
{
cl_git_mkfile("foo", "Dummy file.");
cl_must_pass(p_utimes("foo", times));
- p_stat("foo", &st);
+ cl_must_pass(p_stat("foo", &st));
cl_assert_equal_i(1234567890, st.st_atime);
cl_assert_equal_i(1234567890, st.st_mtime);
cl_must_pass(fd = p_open("foo", O_RDWR));
cl_must_pass(p_futimes(fd, times));
- p_close(fd);
+ cl_must_pass(p_close(fd));
- p_stat("foo", &st);
+ cl_must_pass(p_stat("foo", &st));
cl_assert_equal_i(1414141414, st.st_atime);
cl_assert_equal_i(1414141414, st.st_mtime);
cl_must_pass(p_utimes("foo", NULL));
curtime = time(NULL);
- p_stat("foo", &st);
+ cl_must_pass(p_stat("foo", &st));
cl_assert((st.st_atime - curtime) < 5);
cl_assert((st.st_mtime - curtime) < 5);
- p_unlink("foo");
+ cl_must_pass(p_unlink("foo"));
}
-void test_core_posix__p_regcomp_ignores_global_locale_ctype(void)
+void test_core_posix__unlink_removes_symlink(void)
{
- regex_t preg;
- int error = 0;
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ clar__skip();
- const char* oldlocale = setlocale(LC_CTYPE, NULL);
+ cl_git_mkfile("file", "Dummy file.");
+ cl_git_pass(git_futils_mkdir("dir", 0777, 0));
- if (!setlocale(LC_CTYPE, "UTF-8") &&
- !setlocale(LC_CTYPE, "c.utf8") &&
- !setlocale(LC_CTYPE, "en_US.UTF-8"))
- cl_skip();
+ cl_must_pass(p_symlink("file", "file-symlink"));
+ cl_must_pass(p_symlink("dir", "dir-symlink"));
- if (MB_CUR_MAX == 1) {
- setlocale(LC_CTYPE, oldlocale);
- cl_fail("Expected locale to be switched to multibyte");
- }
+ cl_must_pass(p_unlink("file-symlink"));
+ cl_must_pass(p_unlink("dir-symlink"));
+
+ cl_assert(git_path_exists("file"));
+ cl_assert(git_path_exists("dir"));
- p_regcomp(&preg, "[\xc0-\xff][\x80-\xbf]", REG_EXTENDED);
- regfree(&preg);
+ cl_must_pass(p_unlink("file"));
+ cl_must_pass(p_rmdir("dir"));
+}
+
+void test_core_posix__symlink_resolves_to_correct_type(void)
+{
+ git_buf contents = GIT_BUF_INIT;
- setlocale(LC_CTYPE, oldlocale);
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ clar__skip();
- cl_must_pass(error);
+ cl_must_pass(git_futils_mkdir("dir", 0777, 0));
+ cl_must_pass(git_futils_mkdir("file", 0777, 0));
+ cl_git_mkfile("dir/file", "symlink target");
+
+ cl_git_pass(p_symlink("file", "dir/link"));
+
+ cl_git_pass(git_futils_readbuffer(&contents, "dir/file"));
+ cl_assert_equal_s(contents.ptr, "symlink target");
+
+ cl_must_pass(p_unlink("dir/link"));
+ cl_must_pass(p_unlink("dir/file"));
+ cl_must_pass(p_rmdir("dir"));
+ cl_must_pass(p_rmdir("file"));
+
+ git_buf_dispose(&contents);
}
-void test_core_posix__p_regcomp_compile_userdiff_regexps(void)
+void test_core_posix__relative_symlink(void)
{
- size_t idx;
+ git_buf contents = GIT_BUF_INIT;
- for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) {
- git_diff_driver_definition ddef = builtin_defs[idx];
- int error = 0;
- regex_t preg;
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ clar__skip();
- error = p_regcomp(&preg, ddef.fns, REG_EXTENDED | ddef.flags);
- regfree(&preg);
- cl_must_pass(error);
+ cl_must_pass(git_futils_mkdir("dir", 0777, 0));
+ cl_git_mkfile("file", "contents");
+ cl_git_pass(p_symlink("../file", "dir/link"));
+ cl_git_pass(git_futils_readbuffer(&contents, "dir/link"));
+ cl_assert_equal_s(contents.ptr, "contents");
- error = p_regcomp(&preg, ddef.words, REG_EXTENDED);
- regfree(&preg);
- cl_must_pass(error);
- }
+ cl_must_pass(p_unlink("file"));
+ cl_must_pass(p_unlink("dir/link"));
+ cl_must_pass(p_rmdir("dir"));
+
+ git_buf_dispose(&contents);
+}
+
+void test_core_posix__symlink_to_file_across_dirs(void)
+{
+ git_buf contents = GIT_BUF_INIT;
+
+ if (!git_path_supports_symlinks(clar_sandbox_path()))
+ clar__skip();
+
+ /*
+ * Create a relative symlink that points into another
+ * directory. This used to not work on Win32, where we
+ * forgot to convert directory separators to
+ * Windows-style ones.
+ */
+ cl_must_pass(git_futils_mkdir("dir", 0777, 0));
+ cl_git_mkfile("dir/target", "symlink target");
+ cl_git_pass(p_symlink("dir/target", "link"));
+
+ cl_git_pass(git_futils_readbuffer(&contents, "dir/target"));
+ cl_assert_equal_s(contents.ptr, "symlink target");
+
+ cl_must_pass(p_unlink("dir/target"));
+ cl_must_pass(p_unlink("link"));
+ cl_must_pass(p_rmdir("dir"));
+
+ git_buf_dispose(&contents);
}
--- /dev/null
+#include "clar_libgit2.h"
+
+#define assert_sorted(a, cmp) \
+ _assert_sorted(a, ARRAY_SIZE(a), sizeof(*a), cmp)
+
+struct big_entries {
+ char c[311];
+};
+
+static void _assert_sorted(void *els, size_t n, size_t elsize, git__sort_r_cmp cmp)
+{
+ int8_t *p = els;
+
+ git__qsort_r(p, n, elsize, cmp, NULL);
+ while (n-- > 1) {
+ cl_assert(cmp(p, p + elsize, NULL) <= 0);
+ p += elsize;
+ }
+}
+
+static int cmp_big(const void *_a, const void *_b, void *payload)
+{
+ const struct big_entries *a = (const struct big_entries *)_a, *b = (const struct big_entries *)_b;
+ GIT_UNUSED(payload);
+ return (a->c[0] < b->c[0]) ? -1 : (a->c[0] > b->c[0]) ? +1 : 0;
+}
+
+static int cmp_int(const void *_a, const void *_b, void *payload)
+{
+ int a = *(const int *)_a, b = *(const int *)_b;
+ GIT_UNUSED(payload);
+ return (a < b) ? -1 : (a > b) ? +1 : 0;
+}
+
+static int cmp_str(const void *_a, const void *_b, void *payload)
+{
+ GIT_UNUSED(payload);
+ return strcmp((const char *) _a, (const char *) _b);
+}
+
+void test_core_qsort__array_with_single_entry(void)
+{
+ int a[] = { 10 };
+ assert_sorted(a, cmp_int);
+}
+
+void test_core_qsort__array_with_equal_entries(void)
+{
+ int a[] = { 4, 4, 4, 4 };
+ assert_sorted(a, cmp_int);
+}
+
+void test_core_qsort__sorted_array(void)
+{
+ int a[] = { 1, 10 };
+ assert_sorted(a, cmp_int);
+}
+
+void test_core_qsort__unsorted_array(void)
+{
+ int a[] = { 123, 9, 412938, 10, 234, 89 };
+ assert_sorted(a, cmp_int);
+}
+
+void test_core_qsort__sorting_strings(void)
+{
+ char *a[] = { "foo", "bar", "baz" };
+ assert_sorted(a, cmp_str);
+}
+
+void test_core_qsort__sorting_big_entries(void)
+{
+ struct big_entries a[5];
+
+ memset(&a, 0, sizeof(a));
+
+ memset(a[0].c, 'w', sizeof(a[0].c) - 1);
+ memset(a[1].c, 'c', sizeof(a[1].c) - 1);
+ memset(a[2].c, 'w', sizeof(a[2].c) - 1);
+ memset(a[3].c, 'h', sizeof(a[3].c) - 1);
+ memset(a[4].c, 'a', sizeof(a[4].c) - 1);
+
+ assert_sorted(a, cmp_big);
+
+ cl_assert_equal_i(strspn(a[0].c, "a"), sizeof(a[0].c) - 1);
+ cl_assert_equal_i(strspn(a[1].c, "c"), sizeof(a[1].c) - 1);
+ cl_assert_equal_i(strspn(a[2].c, "h"), sizeof(a[2].c) - 1);
+ cl_assert_equal_i(strspn(a[3].c, "w"), sizeof(a[3].c) - 1);
+ cl_assert_equal_i(strspn(a[4].c, "w"), sizeof(a[4].c) - 1);
+}
--- /dev/null
+#include "clar_libgit2.h"
+
+#include <locale.h>
+
+#include "regexp.h"
+#include "userdiff.h"
+
+#if LC_ALL > 0
+static const char *old_locales[LC_ALL];
+#endif
+
+static git_regexp regex;
+
+void test_core_regexp__initialize(void)
+{
+#if LC_ALL > 0
+ memset(&old_locales, 0, sizeof(old_locales));
+#endif
+}
+
+void test_core_regexp__cleanup(void)
+{
+ git_regexp_dispose(®ex);
+}
+
+static void try_set_locale(int category)
+{
+#if LC_ALL > 0
+ old_locales[category] = setlocale(category, NULL);
+#endif
+
+ if (!setlocale(category, "UTF-8") &&
+ !setlocale(category, "c.utf8") &&
+ !setlocale(category, "en_US.UTF-8"))
+ cl_skip();
+
+ if (MB_CUR_MAX == 1)
+ cl_fail("Expected locale to be switched to multibyte");
+}
+
+
+void test_core_regexp__compile_ignores_global_locale_ctype(void)
+{
+ try_set_locale(LC_CTYPE);
+ cl_git_pass(git_regexp_compile(®ex, "[\xc0-\xff][\x80-\xbf]", 0));
+}
+
+void test_core_regexp__compile_ignores_global_locale_collate(void)
+{
+#ifdef GIT_WIN32
+ cl_skip();
+#endif
+
+ try_set_locale(LC_COLLATE);
+ cl_git_pass(git_regexp_compile(®ex, "[\xc0-\xff][\x80-\xbf]", 0));
+}
+
+void test_core_regexp__regex_matches_digits_with_locale(void)
+{
+ char c, str[2];
+
+#ifdef GIT_WIN32
+ cl_skip();
+#endif
+
+ try_set_locale(LC_COLLATE);
+ try_set_locale(LC_CTYPE);
+
+ cl_git_pass(git_regexp_compile(®ex, "[[:digit:]]", 0));
+
+ str[1] = '\0';
+ for (c = '0'; c <= '9'; c++) {
+ str[0] = c;
+ cl_git_pass(git_regexp_match(®ex, str));
+ }
+}
+
+void test_core_regexp__regex_matches_alphabet_with_locale(void)
+{
+ char c, str[2];
+
+#ifdef GIT_WIN32
+ cl_skip();
+#endif
+
+ try_set_locale(LC_COLLATE);
+ try_set_locale(LC_CTYPE);
+
+ cl_git_pass(git_regexp_compile(®ex, "[[:alpha:]]", 0));
+
+ str[1] = '\0';
+ for (c = 'a'; c <= 'z'; c++) {
+ str[0] = c;
+ cl_git_pass(git_regexp_match(®ex, str));
+ }
+ for (c = 'A'; c <= 'Z'; c++) {
+ str[0] = c;
+ cl_git_pass(git_regexp_match(®ex, str));
+ }
+}
+
+void test_core_regexp__compile_userdiff_regexps(void)
+{
+ size_t idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) {
+ git_diff_driver_definition ddef = builtin_defs[idx];
+
+ cl_git_pass(git_regexp_compile(®ex, ddef.fns, ddef.flags));
+ git_regexp_dispose(®ex);
+
+ cl_git_pass(git_regexp_compile(®ex, ddef.words, 0));
+ git_regexp_dispose(®ex);
+ }
+}
+
+void test_core_regexp__simple_search_matches(void)
+{
+ cl_git_pass(git_regexp_compile(®ex, "a", 0));
+ cl_git_pass(git_regexp_search(®ex, "a", 0, NULL));
+}
+
+void test_core_regexp__case_insensitive_search_matches(void)
+{
+ cl_git_pass(git_regexp_compile(®ex, "a", GIT_REGEXP_ICASE));
+ cl_git_pass(git_regexp_search(®ex, "A", 0, NULL));
+}
+
+void test_core_regexp__nonmatching_search_returns_error(void)
+{
+ cl_git_pass(git_regexp_compile(®ex, "a", 0));
+ cl_git_fail(git_regexp_search(®ex, "b", 0, NULL));
+}
+
+void test_core_regexp__search_finds_complete_match(void)
+{
+ git_regmatch matches[1];
+
+ cl_git_pass(git_regexp_compile(®ex, "abc", 0));
+ cl_git_pass(git_regexp_search(®ex, "abc", 1, matches));
+ cl_assert_equal_i(matches[0].start, 0);
+ cl_assert_equal_i(matches[0].end, 3);
+}
+
+void test_core_regexp__search_finds_correct_offsets(void)
+{
+ git_regmatch matches[3];
+
+ cl_git_pass(git_regexp_compile(®ex, "(a*)(b*)", 0));
+ cl_git_pass(git_regexp_search(®ex, "ab", 3, matches));
+ cl_assert_equal_i(matches[0].start, 0);
+ cl_assert_equal_i(matches[0].end, 2);
+ cl_assert_equal_i(matches[1].start, 0);
+ cl_assert_equal_i(matches[1].end, 1);
+ cl_assert_equal_i(matches[2].start, 1);
+ cl_assert_equal_i(matches[2].end, 2);
+}
+
+void test_core_regexp__search_finds_empty_group(void)
+{
+ git_regmatch matches[3];
+
+ cl_git_pass(git_regexp_compile(®ex, "(a*)(b*)c", 0));
+ cl_git_pass(git_regexp_search(®ex, "ac", 3, matches));
+ cl_assert_equal_i(matches[0].start, 0);
+ cl_assert_equal_i(matches[0].end, 2);
+ cl_assert_equal_i(matches[1].start, 0);
+ cl_assert_equal_i(matches[1].end, 1);
+ cl_assert_equal_i(matches[2].start, 1);
+ cl_assert_equal_i(matches[2].end, 1);
+}
+
+void test_core_regexp__search_fills_matches_with_first_matching_groups(void)
+{
+ git_regmatch matches[2];
+
+ cl_git_pass(git_regexp_compile(®ex, "(a)(b)(c)", 0));
+ cl_git_pass(git_regexp_search(®ex, "abc", 2, matches));
+ cl_assert_equal_i(matches[0].start, 0);
+ cl_assert_equal_i(matches[0].end, 3);
+ cl_assert_equal_i(matches[1].start, 0);
+ cl_assert_equal_i(matches[1].end, 1);
+}
+
+void test_core_regexp__search_skips_nonmatching_group(void)
+{
+ git_regmatch matches[4];
+
+ cl_git_pass(git_regexp_compile(®ex, "(a)(b)?(c)", 0));
+ cl_git_pass(git_regexp_search(®ex, "ac", 4, matches));
+ cl_assert_equal_i(matches[0].start, 0);
+ cl_assert_equal_i(matches[0].end, 2);
+ cl_assert_equal_i(matches[1].start, 0);
+ cl_assert_equal_i(matches[1].end, 1);
+ cl_assert_equal_i(matches[2].start, -1);
+ cl_assert_equal_i(matches[2].end, -1);
+ cl_assert_equal_i(matches[3].start, 1);
+ cl_assert_equal_i(matches[3].end, 2);
+}
+
+void test_core_regexp__search_initializes_trailing_nonmatching_groups(void)
+{
+ git_regmatch matches[3];
+
+ cl_git_pass(git_regexp_compile(®ex, "(a)bc", 0));
+ cl_git_pass(git_regexp_search(®ex, "abc", 3, matches));
+ cl_assert_equal_i(matches[0].start, 0);
+ cl_assert_equal_i(matches[0].end, 3);
+ cl_assert_equal_i(matches[1].start, 0);
+ cl_assert_equal_i(matches[1].end, 1);
+ cl_assert_equal_i(matches[2].start, -1);
+ cl_assert_equal_i(matches[2].end, -1);
+}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
static const char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test";
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "path.h"
#include "posix.h"
#include "clar_libgit2.h"
#include "strmap.h"
-git_strmap *g_table;
+static git_strmap *g_table;
void test_core_strmap__initialize(void)
{
- cl_git_pass(git_strmap_alloc(&g_table));
+ cl_git_pass(git_strmap_new(&g_table));
cl_assert(g_table != NULL);
}
void test_core_strmap__0(void)
{
- cl_assert(git_strmap_num_entries(g_table) == 0);
+ cl_assert(git_strmap_size(g_table) == 0);
}
-static void insert_strings(git_strmap *table, int count)
+static void insert_strings(git_strmap *table, size_t count)
{
- int i, j, over, err;
+ size_t i, j, over;
char *str;
for (i = 0; i < count; ++i) {
for (j = 0, over = i / 26; over > 0; j++, over = over / 26)
str[j] = 'A' + (over % 26);
- git_strmap_insert(table, str, str, &err);
- cl_assert(err >= 0);
+ cl_git_pass(git_strmap_set(table, str, str));
}
- cl_assert((int)git_strmap_num_entries(table) == count);
+ cl_assert_equal_i(git_strmap_size(table), count);
}
-void test_core_strmap__1(void)
+void test_core_strmap__inserted_strings_can_be_retrieved(void)
{
- int i;
char *str;
+ int i;
insert_strings(g_table, 20);
cl_assert(i == 20);
}
-void test_core_strmap__2(void)
+void test_core_strmap__deleted_entry_cannot_be_retrieved(void)
{
- size_t pos;
- int i;
char *str;
+ int i;
insert_strings(g_table, 20);
- cl_assert(git_strmap_exists(g_table, "aaaaaaaaa"));
- cl_assert(git_strmap_exists(g_table, "ggggggggg"));
- cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
- cl_assert(!git_strmap_exists(g_table, "abcdefghi"));
-
cl_assert(git_strmap_exists(g_table, "bbbbbbbbb"));
- pos = git_strmap_lookup_index(g_table, "bbbbbbbbb");
- cl_assert(git_strmap_valid_index(g_table, pos));
- cl_assert_equal_s(git_strmap_value_at(g_table, pos), "bbbbbbbbb");
- free(git_strmap_value_at(g_table, pos));
- git_strmap_delete_at(g_table, pos);
+ str = git_strmap_get(g_table, "bbbbbbbbb");
+ cl_assert_equal_s(str, "bbbbbbbbb");
+ cl_git_pass(git_strmap_delete(g_table, "bbbbbbbbb"));
+ free(str);
cl_assert(!git_strmap_exists(g_table, "bbbbbbbbb"));
i = 0;
git_strmap_foreach_value(g_table, str, { i++; free(str); });
- cl_assert(i == 19);
+ cl_assert_equal_i(i, 19);
}
-void test_core_strmap__3(void)
+void test_core_strmap__inserting_many_keys_succeeds(void)
{
- int i;
char *str;
+ int i;
insert_strings(g_table, 10000);
i = 0;
git_strmap_foreach_value(g_table, str, { i++; free(str); });
- cl_assert(i == 10000);
+ cl_assert_equal_i(i, 10000);
+}
+
+void test_core_strmap__get_succeeds_with_existing_entries(void)
+{
+ const char *keys[] = { "foo", "bar", "gobble" };
+ char *values[] = { "oof", "rab", "elbbog" };
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(keys); i++)
+ cl_git_pass(git_strmap_set(g_table, keys[i], values[i]));
+
+ cl_assert_equal_s(git_strmap_get(g_table, "foo"), "oof");
+ cl_assert_equal_s(git_strmap_get(g_table, "bar"), "rab");
+ cl_assert_equal_s(git_strmap_get(g_table, "gobble"), "elbbog");
+}
+
+void test_core_strmap__get_returns_null_on_nonexisting_key(void)
+{
+ const char *keys[] = { "foo", "bar", "gobble" };
+ char *values[] = { "oof", "rab", "elbbog" };
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(keys); i++)
+ cl_git_pass(git_strmap_set(g_table, keys[i], values[i]));
+
+ cl_assert_equal_p(git_strmap_get(g_table, "other"), NULL);
+}
+
+void test_core_strmap__set_persists_key(void)
+{
+ cl_git_pass(git_strmap_set(g_table, "foo", "oof"));
+ cl_assert_equal_s(git_strmap_get(g_table, "foo"), "oof");
+}
+
+void test_core_strmap__set_persists_multpile_keys(void)
+{
+ cl_git_pass(git_strmap_set(g_table, "foo", "oof"));
+ cl_git_pass(git_strmap_set(g_table, "bar", "rab"));
+ cl_assert_equal_s(git_strmap_get(g_table, "foo"), "oof");
+ cl_assert_equal_s(git_strmap_get(g_table, "bar"), "rab");
+}
+
+void test_core_strmap__set_updates_existing_key(void)
+{
+ cl_git_pass(git_strmap_set(g_table, "foo", "oof"));
+ cl_git_pass(git_strmap_set(g_table, "bar", "rab"));
+ cl_git_pass(git_strmap_set(g_table, "gobble", "elbbog"));
+ cl_assert_equal_i(git_strmap_size(g_table), 3);
+
+ cl_git_pass(git_strmap_set(g_table, "foo", "other"));
+ cl_assert_equal_i(git_strmap_size(g_table), 3);
+
+ cl_assert_equal_s(git_strmap_get(g_table, "foo"), "other");
+}
+
+void test_core_strmap__iteration(void)
+{
+ struct {
+ char *key;
+ char *value;
+ int seen;
+ } entries[] = {
+ { "foo", "oof" },
+ { "bar", "rab" },
+ { "gobble", "elbbog" },
+ };
+ const char *key, *value;
+ size_t i, n;
+
+ for (i = 0; i < ARRAY_SIZE(entries); i++)
+ cl_git_pass(git_strmap_set(g_table, entries[i].key, entries[i].value));
+
+ i = 0, n = 0;
+ while (git_strmap_iterate((void **) &value, g_table, &i, &key) == 0) {
+ size_t j;
+
+ for (j = 0; j < ARRAY_SIZE(entries); j++) {
+ if (strcmp(entries[j].key, key))
+ continue;
+
+ cl_assert_equal_i(entries[j].seen, 0);
+ cl_assert_equal_s(entries[j].value, value);
+ entries[j].seen++;
+ break;
+ }
+
+ n++;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(entries); i++)
+ cl_assert_equal_i(entries[i].seen, 1);
+
+ cl_assert_equal_i(n, ARRAY_SIZE(entries));
+}
+
+void test_core_strmap__iterating_empty_map_stops_immediately(void)
+{
+ size_t i = 0;
+
+ cl_git_fail_with(git_strmap_iterate(NULL, g_table, &i, NULL), GIT_ITEROVER);
}
p_snprintf(desc, 1024, "Difference in %s at byte %" PRIuZ ": macro=%u / func=%u",
name, i, ((char *)one)[i], ((char *)two)[i]);
- clar__fail(__FILE__, __LINE__,
+ clar__fail(__FILE__, __func__, __LINE__,
"Difference between macro and function options initializer",
desc, 0);
return;
clar__skip();
#endif
+ /* apply */
+ CHECK_MACRO_FUNC_INIT_EQUAL( \
+ git_apply_options, GIT_APPLY_OPTIONS_VERSION, \
+ GIT_APPLY_OPTIONS_INIT, git_apply_options_init);
+
/* blame */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_blame_options, GIT_BLAME_OPTIONS_VERSION, \
- GIT_BLAME_OPTIONS_INIT, git_blame_init_options);
+ GIT_BLAME_OPTIONS_INIT, git_blame_options_init);
/* checkout */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, \
- GIT_CHECKOUT_OPTIONS_INIT, git_checkout_init_options);
+ GIT_CHECKOUT_OPTIONS_INIT, git_checkout_options_init);
/* clone */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_clone_options, GIT_CLONE_OPTIONS_VERSION, \
- GIT_CLONE_OPTIONS_INIT, git_clone_init_options);
+ GIT_CLONE_OPTIONS_INIT, git_clone_options_init);
/* diff */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_diff_options, GIT_DIFF_OPTIONS_VERSION, \
- GIT_DIFF_OPTIONS_INIT, git_diff_init_options);
+ GIT_DIFF_OPTIONS_INIT, git_diff_options_init);
/* diff_find */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_diff_find_options, GIT_DIFF_FIND_OPTIONS_VERSION, \
- GIT_DIFF_FIND_OPTIONS_INIT, git_diff_find_init_options);
+ GIT_DIFF_FIND_OPTIONS_INIT, git_diff_find_options_init);
/* filter */
CHECK_MACRO_FUNC_INIT_EQUAL( \
/* merge_file_input */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_merge_file_input, GIT_MERGE_FILE_INPUT_VERSION, \
- GIT_MERGE_FILE_INPUT_INIT, git_merge_file_init_input);
+ GIT_MERGE_FILE_INPUT_INIT, git_merge_file_input_init);
/* merge_file */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_merge_file_options, GIT_MERGE_FILE_OPTIONS_VERSION, \
- GIT_MERGE_FILE_OPTIONS_INIT, git_merge_file_init_options);
+ GIT_MERGE_FILE_OPTIONS_INIT, git_merge_file_options_init);
/* merge_tree */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_merge_options, GIT_MERGE_OPTIONS_VERSION, \
- GIT_MERGE_OPTIONS_INIT, git_merge_init_options);
+ GIT_MERGE_OPTIONS_INIT, git_merge_options_init);
/* push */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_push_options, GIT_PUSH_OPTIONS_VERSION, \
- GIT_PUSH_OPTIONS_INIT, git_push_init_options);
+ GIT_PUSH_OPTIONS_INIT, git_push_options_init);
/* remote */
CHECK_MACRO_FUNC_INIT_EQUAL( \
/* repository_init */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_repository_init_options, GIT_REPOSITORY_INIT_OPTIONS_VERSION, \
- GIT_REPOSITORY_INIT_OPTIONS_INIT, git_repository_init_init_options);
+ GIT_REPOSITORY_INIT_OPTIONS_INIT, git_repository_init_options_init);
/* revert */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_revert_options, GIT_REVERT_OPTIONS_VERSION, \
- GIT_REVERT_OPTIONS_INIT, git_revert_init_options);
+ GIT_REVERT_OPTIONS_INIT, git_revert_options_init);
/* stash apply */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_stash_apply_options, GIT_STASH_APPLY_OPTIONS_VERSION, \
- GIT_STASH_APPLY_OPTIONS_INIT, git_stash_apply_init_options);
+ GIT_STASH_APPLY_OPTIONS_INIT, git_stash_apply_options_init);
/* status */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_status_options, GIT_STATUS_OPTIONS_VERSION, \
- GIT_STATUS_OPTIONS_INIT, git_status_init_options);
+ GIT_STATUS_OPTIONS_INIT, git_status_options_init);
/* transport */
CHECK_MACRO_FUNC_INIT_EQUAL( \
/* submodule update */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, \
- GIT_SUBMODULE_UPDATE_OPTIONS_INIT, git_submodule_update_init_options);
+ GIT_SUBMODULE_UPDATE_OPTIONS_INIT, git_submodule_update_options_init);
/* submodule update */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_proxy_options, GIT_PROXY_OPTIONS_VERSION, \
- GIT_PROXY_OPTIONS_INIT, git_proxy_init_options);
+ GIT_PROXY_OPTIONS_INIT, git_proxy_options_init);
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_VERSION, \
- GIT_DIFF_PATCHID_OPTIONS_INIT, git_diff_patchid_init_options);
+ GIT_DIFF_PATCHID_OPTIONS_INIT, git_diff_patchid_options_init);
}
--- /dev/null
+#include "clar_libgit2.h"
+
+#include "wildmatch.h"
+
+#define assert_matches(string, pattern, wildmatch, iwildmatch, pathmatch, ipathmatch) \
+ assert_matches_(string, pattern, wildmatch, iwildmatch, pathmatch, ipathmatch, __FILE__, __func__, __LINE__)
+
+static void assert_matches_(const char *string, const char *pattern,
+ char expected_wildmatch, char expected_iwildmatch,
+ char expected_pathmatch, char expected_ipathmatch,
+ const char *file, const char *func, size_t line)
+{
+ if (wildmatch(pattern, string, WM_PATHNAME) == expected_wildmatch)
+ clar__fail(file, func, line, "Test failed (wildmatch).", string, 1);
+ if (wildmatch(pattern, string, WM_PATHNAME|WM_CASEFOLD) == expected_iwildmatch)
+ clar__fail(file, func, line, "Test failed (iwildmatch).", string, 1);
+ if (wildmatch(pattern, string, 0) == expected_pathmatch)
+ clar__fail(file, func, line, "Test failed (pathmatch).", string, 1);
+ if (wildmatch(pattern, string, WM_CASEFOLD) == expected_ipathmatch)
+ clar__fail(file, func, line, "Test failed (ipathmatch).", string, 1);
+}
+
+/*
+ * Below testcases are imported from git.git, t3070-wildmatch,sh at tag v2.22.0.
+ * Note that we've only imported the direct wildcard tests, but not the matching
+ * tests for git-ls-files.
+ */
+
+void test_core_wildmatch__basic_wildmatch(void)
+{
+ assert_matches("foo", "foo", 1, 1, 1, 1);
+ assert_matches("foo", "bar", 0, 0, 0, 0);
+ assert_matches("", "", 1, 1, 1, 1);
+ assert_matches("foo", "???", 1, 1, 1, 1);
+ assert_matches("foo", "??", 0, 0, 0, 0);
+ assert_matches("foo", "*", 1, 1, 1, 1);
+ assert_matches("foo", "f*", 1, 1, 1, 1);
+ assert_matches("foo", "*f", 0, 0, 0, 0);
+ assert_matches("foo", "*foo*", 1, 1, 1, 1);
+ assert_matches("foobar", "*ob*a*r*", 1, 1, 1, 1);
+ assert_matches("aaaaaaabababab", "*ab", 1, 1, 1, 1);
+ assert_matches("foo*", "foo\\*", 1, 1, 1, 1);
+ assert_matches("foobar", "foo\\*bar", 0, 0, 0, 0);
+ assert_matches("f\\oo", "f\\\\oo", 1, 1, 1, 1);
+ assert_matches("ball", "*[al]?", 1, 1, 1, 1);
+ assert_matches("ten", "[ten]", 0, 0, 0, 0);
+ assert_matches("ten", "**[!te]", 1, 1, 1, 1);
+ assert_matches("ten", "**[!ten]", 0, 0, 0, 0);
+ assert_matches("ten", "t[a-g]n", 1, 1, 1, 1);
+ assert_matches("ten", "t[!a-g]n", 0, 0, 0, 0);
+ assert_matches("ton", "t[!a-g]n", 1, 1, 1, 1);
+ assert_matches("ton", "t[^a-g]n", 1, 1, 1, 1);
+ assert_matches("a]b", "a[]]b", 1, 1, 1, 1);
+ assert_matches("a-b", "a[]-]b", 1, 1, 1, 1);
+ assert_matches("a]b", "a[]-]b", 1, 1, 1, 1);
+ assert_matches("aab", "a[]-]b", 0, 0, 0, 0);
+ assert_matches("aab", "a[]a-]b", 1, 1, 1, 1);
+ assert_matches("]", "]", 1, 1, 1, 1);
+}
+
+void test_core_wildmatch__slash_matching_features(void)
+{
+ assert_matches("foo/baz/bar", "foo*bar", 0, 0, 1, 1);
+ assert_matches("foo/baz/bar", "foo**bar", 0, 0, 1, 1);
+ assert_matches("foobazbar", "foo**bar", 1, 1, 1, 1);
+ assert_matches("foo/baz/bar", "foo/**/bar", 1, 1, 1, 1);
+ assert_matches("foo/baz/bar", "foo/**/**/bar", 1, 1, 0, 0);
+ assert_matches("foo/b/a/z/bar", "foo/**/bar", 1, 1, 1, 1);
+ assert_matches("foo/b/a/z/bar", "foo/**/**/bar", 1, 1, 1, 1);
+ assert_matches("foo/bar", "foo/**/bar", 1, 1, 0, 0);
+ assert_matches("foo/bar", "foo/**/**/bar", 1, 1, 0, 0);
+ assert_matches("foo/bar", "foo?bar", 0, 0, 1, 1);
+ assert_matches("foo/bar", "foo[/]bar", 0, 0, 1, 1);
+ assert_matches("foo/bar", "foo[^a-z]bar", 0, 0, 1, 1);
+ assert_matches("foo/bar", "f[^eiu][^eiu][^eiu][^eiu][^eiu]r", 0, 0, 1, 1);
+ assert_matches("foo-bar", "f[^eiu][^eiu][^eiu][^eiu][^eiu]r", 1, 1, 1, 1);
+ assert_matches("foo", "**/foo", 1, 1, 0, 0);
+ assert_matches("XXX/foo", "**/foo", 1, 1, 1, 1);
+ assert_matches("bar/baz/foo", "**/foo", 1, 1, 1, 1);
+ assert_matches("bar/baz/foo", "*/foo", 0, 0, 1, 1);
+ assert_matches("foo/bar/baz", "**/bar*", 0, 0, 1, 1);
+ assert_matches("deep/foo/bar/baz", "**/bar/*", 1, 1, 1, 1);
+ assert_matches("deep/foo/bar/baz/", "**/bar/*", 0, 0, 1, 1);
+ assert_matches("deep/foo/bar/baz/", "**/bar/**", 1, 1, 1, 1);
+ assert_matches("deep/foo/bar", "**/bar/*", 0, 0, 0, 0);
+ assert_matches("deep/foo/bar/", "**/bar/**", 1, 1, 1, 1);
+ assert_matches("foo/bar/baz", "**/bar**", 0, 0, 1, 1);
+ assert_matches("foo/bar/baz/x", "*/bar/**", 1, 1, 1, 1);
+ assert_matches("deep/foo/bar/baz/x", "*/bar/**", 0, 0, 1, 1);
+ assert_matches("deep/foo/bar/baz/x", "**/bar/*/*", 1, 1, 1, 1);
+}
+
+void test_core_wildmatch__various_additional(void)
+{
+ assert_matches("acrt", "a[c-c]st", 0, 0, 0, 0);
+ assert_matches("acrt", "a[c-c]rt", 1, 1, 1, 1);
+ assert_matches("]", "[!]-]", 0, 0, 0, 0);
+ assert_matches("a", "[!]-]", 1, 1, 1, 1);
+ assert_matches("", "\\", 0, 0, 0, 0);
+ assert_matches("\\", "\\", 0, 0, 0, 0);
+ assert_matches("XXX/\\", "*/\\", 0, 0, 0, 0);
+ assert_matches("XXX/\\", "*/\\\\", 1, 1, 1, 1);
+ assert_matches("foo", "foo", 1, 1, 1, 1);
+ assert_matches("@foo", "@foo", 1, 1, 1, 1);
+ assert_matches("foo", "@foo", 0, 0, 0, 0);
+ assert_matches("[ab]", "\\[ab]", 1, 1, 1, 1);
+ assert_matches("[ab]", "[[]ab]", 1, 1, 1, 1);
+ assert_matches("[ab]", "[[:]ab]", 1, 1, 1, 1);
+ assert_matches("[ab]", "[[::]ab]", 0, 0, 0, 0);
+ assert_matches("[ab]", "[[:digit]ab]", 1, 1, 1, 1);
+ assert_matches("[ab]", "[\\[:]ab]", 1, 1, 1, 1);
+ assert_matches("?a?b", "\\??\\?b", 1, 1, 1, 1);
+ assert_matches("abc", "\\a\\b\\c", 1, 1, 1, 1);
+ assert_matches("foo", "", 0, 0, 0, 0);
+ assert_matches("foo/bar/baz/to", "**/t[o]", 1, 1, 1, 1);
+}
+
+void test_core_wildmatch__character_classes(void)
+{
+ assert_matches("a1B", "[[:alpha:]][[:digit:]][[:upper:]]", 1, 1, 1, 1);
+ assert_matches("a", "[[:digit:][:upper:][:space:]]", 0, 1, 0, 1);
+ assert_matches("A", "[[:digit:][:upper:][:space:]]", 1, 1, 1, 1);
+ assert_matches("1", "[[:digit:][:upper:][:space:]]", 1, 1, 1, 1);
+ assert_matches("1", "[[:digit:][:upper:][:spaci:]]", 0, 0, 0, 0);
+ assert_matches(" ", "[[:digit:][:upper:][:space:]]", 1, 1, 1, 1);
+ assert_matches(".", "[[:digit:][:upper:][:space:]]", 0, 0, 0, 0);
+ assert_matches(".", "[[:digit:][:punct:][:space:]]", 1, 1, 1, 1);
+ assert_matches("5", "[[:xdigit:]]", 1, 1, 1, 1);
+ assert_matches("f", "[[:xdigit:]]", 1, 1, 1, 1);
+ assert_matches("D", "[[:xdigit:]]", 1, 1, 1, 1);
+ assert_matches("_", "[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]", 1, 1, 1, 1);
+ assert_matches(".", "[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]", 1, 1, 1, 1);
+ assert_matches("5", "[a-c[:digit:]x-z]", 1, 1, 1, 1);
+ assert_matches("b", "[a-c[:digit:]x-z]", 1, 1, 1, 1);
+ assert_matches("y", "[a-c[:digit:]x-z]", 1, 1, 1, 1);
+ assert_matches("q", "[a-c[:digit:]x-z]", 0, 0, 0, 0);
+}
+
+void test_core_wildmatch__additional_with_malformed(void)
+{
+ assert_matches("]", "[\\\\-^]", 1, 1, 1, 1);
+ assert_matches("[", "[\\\\-^]", 0, 0, 0, 0);
+ assert_matches("-", "[\\-_]", 1, 1, 1, 1);
+ assert_matches("]", "[\\]]", 1, 1, 1, 1);
+ assert_matches("\\]", "[\\]]", 0, 0, 0, 0);
+ assert_matches("\\", "[\\]]", 0, 0, 0, 0);
+ assert_matches("ab", "a[]b", 0, 0, 0, 0);
+ assert_matches("a[]b", "a[]b", 0, 0, 0, 0);
+ assert_matches("ab[", "ab[", 0, 0, 0, 0);
+ assert_matches("ab", "[!", 0, 0, 0, 0);
+ assert_matches("ab", "[-", 0, 0, 0, 0);
+ assert_matches("-", "[-]", 1, 1, 1, 1);
+ assert_matches("-", "[a-", 0, 0, 0, 0);
+ assert_matches("-", "[!a-", 0, 0, 0, 0);
+ assert_matches("-", "[--A]", 1, 1, 1, 1);
+ assert_matches("5", "[--A]", 1, 1, 1, 1);
+ assert_matches(" ", "[ --]", 1, 1, 1, 1);
+ assert_matches("$", "[ --]", 1, 1, 1, 1);
+ assert_matches("-", "[ --]", 1, 1, 1, 1);
+ assert_matches("0", "[ --]", 0, 0, 0, 0);
+ assert_matches("-", "[---]", 1, 1, 1, 1);
+ assert_matches("-", "[------]", 1, 1, 1, 1);
+ assert_matches("j", "[a-e-n]", 0, 0, 0, 0);
+ assert_matches("-", "[a-e-n]", 1, 1, 1, 1);
+ assert_matches("a", "[!------]", 1, 1, 1, 1);
+ assert_matches("[", "[]-a]", 0, 0, 0, 0);
+ assert_matches("^", "[]-a]", 1, 1, 1, 1);
+ assert_matches("^", "[!]-a]", 0, 0, 0, 0);
+ assert_matches("[", "[!]-a]", 1, 1, 1, 1);
+ assert_matches("^", "[a^bc]", 1, 1, 1, 1);
+ assert_matches("-b]", "[a-]b]", 1, 1, 1, 1);
+ assert_matches("\\", "[\\]", 0, 0, 0, 0);
+ assert_matches("\\", "[\\\\]", 1, 1, 1, 1);
+ assert_matches("\\", "[!\\\\]", 0, 0, 0, 0);
+ assert_matches("G", "[A-\\\\]", 1, 1, 1, 1);
+ assert_matches("aaabbb", "b*a", 0, 0, 0, 0);
+ assert_matches("aabcaa", "*ba*", 0, 0, 0, 0);
+ assert_matches(",", "[,]", 1, 1, 1, 1);
+ assert_matches(",", "[\\\\,]", 1, 1, 1, 1);
+ assert_matches("\\", "[\\\\,]", 1, 1, 1, 1);
+ assert_matches("-", "[,-.]", 1, 1, 1, 1);
+ assert_matches("+", "[,-.]", 0, 0, 0, 0);
+ assert_matches("-.]", "[,-.]", 0, 0, 0, 0);
+ assert_matches("2", "[\\1-\\3]", 1, 1, 1, 1);
+ assert_matches("3", "[\\1-\\3]", 1, 1, 1, 1);
+ assert_matches("4", "[\\1-\\3]", 0, 0, 0, 0);
+ assert_matches("\\", "[[-\\]]", 1, 1, 1, 1);
+ assert_matches("[", "[[-\\]]", 1, 1, 1, 1);
+ assert_matches("]", "[[-\\]]", 1, 1, 1, 1);
+ assert_matches("-", "[[-\\]]", 0, 0, 0, 0);
+}
+
+void test_core_wildmatch__recursion(void)
+{
+ assert_matches("-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1", "-*-*-*-*-*-*-12-*-*-*-m-*-*-*", 1, 1, 1, 1);
+ assert_matches("-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1", "-*-*-*-*-*-*-12-*-*-*-m-*-*-*", 0, 0, 0, 0);
+ assert_matches("-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1", "-*-*-*-*-*-*-12-*-*-*-m-*-*-*", 0, 0, 0, 0);
+ assert_matches("XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1", "XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*", 1, 1, 1, 1);
+ assert_matches("XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1", "XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*", 0, 0, 0, 0);
+ assert_matches("abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt", "**/*a*b*g*n*t", 1, 1, 1, 1);
+ assert_matches("abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz", "**/*a*b*g*n*t", 0, 0, 0, 0);
+ assert_matches("foo", "*/*/*", 0, 0, 0, 0);
+ assert_matches("foo/bar", "*/*/*", 0, 0, 0, 0);
+ assert_matches("foo/bba/arr", "*/*/*", 1, 1, 1, 1);
+ assert_matches("foo/bb/aa/rr", "*/*/*", 0, 0, 1, 1);
+ assert_matches("foo/bb/aa/rr", "**/**/**", 1, 1, 1, 1);
+ assert_matches("abcXdefXghi", "*X*i", 1, 1, 1, 1);
+ assert_matches("ab/cXd/efXg/hi", "*X*i", 0, 0, 1, 1);
+ assert_matches("ab/cXd/efXg/hi", "*/*X*/*/*i", 1, 1, 1, 1);
+ assert_matches("ab/cXd/efXg/hi", "**/*X*/**/*i", 1, 1, 1, 1);
+}
+
+void test_core_wildmatch__pathmatch(void)
+{
+ assert_matches("foo", "fo", 0, 0, 0, 0);
+ assert_matches("foo/bar", "foo/bar", 1, 1, 1, 1);
+ assert_matches("foo/bar", "foo/*", 1, 1, 1, 1);
+ assert_matches("foo/bba/arr", "foo/*", 0, 0, 1, 1);
+ assert_matches("foo/bba/arr", "foo/**", 1, 1, 1, 1);
+ assert_matches("foo/bba/arr", "foo*", 0, 0, 1, 1);
+ assert_matches("foo/bba/arr", "foo**", 0, 0, 1, 1);
+ assert_matches("foo/bba/arr", "foo/*arr", 0, 0, 1, 1);
+ assert_matches("foo/bba/arr", "foo/**arr", 0, 0, 1, 1);
+ assert_matches("foo/bba/arr", "foo/*z", 0, 0, 0, 0);
+ assert_matches("foo/bba/arr", "foo/**z", 0, 0, 0, 0);
+ assert_matches("foo/bar", "foo?bar", 0, 0, 1, 1);
+ assert_matches("foo/bar", "foo[/]bar", 0, 0, 1, 1);
+ assert_matches("foo/bar", "foo[^a-z]bar", 0, 0, 1, 1);
+ assert_matches("ab/cXd/efXg/hi", "*Xg*i", 0, 0, 1, 1);
+}
+
+void test_core_wildmatch__case_sensitivity(void)
+{
+ assert_matches("a", "[A-Z]", 0, 1, 0, 1);
+ assert_matches("A", "[A-Z]", 1, 1, 1, 1);
+ assert_matches("A", "[a-z]", 0, 1, 0, 1);
+ assert_matches("a", "[a-z]", 1, 1, 1, 1);
+ assert_matches("a", "[[:upper:]]", 0, 1, 0, 1);
+ assert_matches("A", "[[:upper:]]", 1, 1, 1, 1);
+ assert_matches("A", "[[:lower:]]", 0, 1, 0, 1);
+ assert_matches("a", "[[:lower:]]", 1, 1, 1, 1);
+ assert_matches("A", "[B-Za]", 0, 1, 0, 1);
+ assert_matches("a", "[B-Za]", 1, 1, 1, 1);
+ assert_matches("A", "[B-a]", 0, 1, 0, 1);
+ assert_matches("a", "[B-a]", 1, 1, 1, 1);
+ assert_matches("z", "[Z-y]", 0, 1, 0, 1);
+ assert_matches("Z", "[Z-y]", 1, 1, 1, 1);
+}
static void assert_zlib_equal_(
const void *expected, size_t e_len,
const void *compressed, size_t c_len,
- const char *msg, const char *file, int line)
+ const char *msg, const char *file, const char *func, int line)
{
z_stream stream;
char *expanded = git__calloc(1, e_len + INFLATE_EXTRA);
inflateEnd(&stream);
clar__assert_equal(
- file, line, msg, 1,
+ file, func, line, msg, 1,
"%d", (int)stream.total_out, (int)e_len);
clar__assert_equal(
- file, line, "Buffer len was not exact match", 1,
+ file, func, line, "Buffer len was not exact match", 1,
"%d", (int)stream.avail_out, (int)INFLATE_EXTRA);
clar__assert(
memcmp(expanded, expected, e_len) == 0,
- file, line, "uncompressed data did not match", NULL, 1);
+ file, func, line, "uncompressed data did not match", NULL, 1);
git__free(expanded);
}
#define assert_zlib_equal(E,EL,C,CL) \
- assert_zlib_equal_(E, EL, C, CL, #EL " != " #CL, __FILE__, (int)__LINE__)
+ assert_zlib_equal_(E, EL, C, CL, #EL " != " #CL, __FILE__, __func__, (int)__LINE__)
void test_core_zstream__basic(void)
{
#include "describe_helpers.h"
+#include "wildmatch.h"
+
void assert_describe(
const char *expected_output,
const char *revparse_spec,
cl_git_pass(git_describe_commit(&result, object, opts));
cl_git_pass(git_describe_format(&label, result, fmt_opts));
- cl_must_pass(p_fnmatch(expected_output, git_buf_cstr(&label), 0));
+ cl_must_pass(wildmatch(expected_output, git_buf_cstr(&label), 0));
git_describe_result_free(result);
git_object_free(object);
cl_git_pass(git_describe_workdir(&result, repo, opts));
cl_git_pass(git_describe_format(&label, result, fmt_opts));
- cl_must_pass(p_fnmatch(expected_output, git_buf_cstr(&label), 0));
+ cl_must_pass(wildmatch(expected_output, git_buf_cstr(&label), 0));
git_describe_result_free(result);
git_buf_dispose(&label);
g_repo = cl_git_sandbox_init("attr");
- cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
+ cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION));
opts.context_lines = 1;
memset(&expected, 0, sizeof(expected));
cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size);
- cl_assert(git_oid_iszero(&delta->new_file.id));
+ cl_assert(git_oid_is_zero(&delta->new_file.id));
cl_assert_equal_sz(0, delta->new_file.size);
cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
delta = git_patch_get_delta(p);
cl_assert(delta != NULL);
cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
- cl_assert(git_oid_iszero(&delta->old_file.id));
+ cl_assert(git_oid_is_zero(&delta->old_file.id));
cl_assert_equal_sz(0, delta->old_file.size);
cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);
cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);
cl_assert(delta != NULL);
cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
cl_assert_equal_sz(0, delta->old_file.size);
- cl_assert(git_oid_iszero(&delta->old_file.id));
+ cl_assert(git_oid_is_zero(&delta->old_file.id));
cl_assert_equal_sz(0, delta->new_file.size);
- cl_assert(git_oid_iszero(&delta->new_file.id));
+ cl_assert(git_oid_is_zero(&delta->new_file.id));
cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
git_patch_free(p);
* +++ b/a0f7217
* @@ -1,6 +1,6 @@
* Here is some stuff at the start
- *
+ *
* -This should go in one hunk
* +This should go in one hunk (first)
- *
+ *
* Some additional lines
- *
+ *
* @@ -8,7 +8,7 @@ Down here below the other lines
- *
+ *
* With even more at the end
- *
+ *
* -Followed by a second hunk of stuff
* +Followed by a second hunk of stuff (second)
- *
+ *
* That happens down here
*/
void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void)
-#include "fileops.h"
+#include "futils.h"
#include "git2/diff.h"
extern git_tree *resolve_commit_oid_to_tree(
"Subject: [PATCH] Modified binary file\n" \
"\n" \
"---\n" \
- " binary.bin | Bin 3 -> 0 bytes\n" \
+ " binary.bin | Bin 3 -> 5 bytes\n" \
" 1 file changed, 0 insertions(+), 0 deletions(-)\n" \
"\n" \
"diff --git a/binary.bin b/binary.bin\n" \
"--\n" \
"libgit2 " LIBGIT2_VERSION "\n" \
"\n";
- /* TODO: Actually 0 bytes here should be 5!. Seems like we don't load the new content for binary files? */
opts.summary = "Modified binary file";
#include "patch.h"
#include "patch_parse.h"
#include "diff_helpers.h"
-#include "../src/diff.h"
#include "../patch/patch_common.h"
git_diff_free(diff);
}
+void test_diff_parse__empty_file(void)
+{
+ const char *content =
+ "---\n"
+ " file | 0\n"
+ " 1 file changed, 0 insertions(+), 0 deletions(-)\n"
+ " created mode 100644 file\n"
+ "\n"
+ "diff --git a/file b/file\n"
+ "new file mode 100644\n"
+ "index 0000000..e69de29\n"
+ "-- \n"
+ "2.20.1\n";
+ git_diff *diff;
+
+ cl_git_pass(git_diff_from_buffer(
+ &diff, content, strlen(content)));
+ git_diff_free(diff);
+}
+
+void test_diff_parse__no_extended_headers(void)
+{
+ const char *content = PATCH_NO_EXTENDED_HEADERS;
+ git_diff *diff;
+
+ cl_git_pass(git_diff_from_buffer(
+ &diff, content, strlen(content)));
+ git_diff_free(diff);
+}
+
+void test_diff_parse__add_delete_no_index(void)
+{
+ const char *content =
+ "diff --git a/file.txt b/file.txt\n"
+ "new file mode 100644\n"
+ "--- /dev/null\n"
+ "+++ b/file.txt\n"
+ "@@ -0,0 +1,2 @@\n"
+ "+one\n"
+ "+two\n"
+ "diff --git a/otherfile.txt b/otherfile.txt\n"
+ "deleted file mode 100644\n"
+ "--- a/otherfile.txt\n"
+ "+++ /dev/null\n"
+ "@@ -1,1 +0,0 @@\n"
+ "-three\n";
+ git_diff *diff;
+
+ cl_git_pass(git_diff_from_buffer(
+ &diff, content, strlen(content)));
+ git_diff_free(diff);
+}
+
void test_diff_parse__invalid_patches_fails(void)
{
test_parse_invalid_diff(PATCH_CORRUPT_MISSING_NEW_FILE);
git_buf_dispose(&diffbuf);
}
-#define cl_assert_equal_i_src(i1,i2,file,line) clar__assert_equal(file,line,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
+#define cl_assert_equal_i_src(i1,i2,file,func,line) clar__assert_equal(file,func,line,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
-static void cl_git_assert_lineinfo_(int old_lineno, int new_lineno, int num_lines, git_patch *patch, size_t hunk_idx, size_t line_idx, const char *file, int lineno)
+static void cl_git_assert_lineinfo_(int old_lineno, int new_lineno, int num_lines, git_patch *patch, size_t hunk_idx, size_t line_idx, const char *file, const char *func, int lineno)
{
const git_diff_line *line;
- cl_git_expect(git_patch_get_line_in_hunk(&line, patch, hunk_idx, line_idx), 0, file, lineno);
- cl_assert_equal_i_src(old_lineno, line->old_lineno, file, lineno);
- cl_assert_equal_i_src(new_lineno, line->new_lineno, file, lineno);
- cl_assert_equal_i_src(num_lines, line->num_lines, file, lineno);
+ cl_git_expect(git_patch_get_line_in_hunk(&line, patch, hunk_idx, line_idx), 0, file, func, lineno);
+ cl_assert_equal_i_src(old_lineno, line->old_lineno, file, func, lineno);
+ cl_assert_equal_i_src(new_lineno, line->new_lineno, file, func, lineno);
+ cl_assert_equal_i_src(num_lines, line->num_lines, file, func, lineno);
}
#define cl_git_assert_lineinfo(old, new, num, p, h, l) \
- cl_git_assert_lineinfo_(old,new,num,p,h,l,__FILE__,__LINE__)
+ cl_git_assert_lineinfo_(old,new,num,p,h,l,__FILE__,__func__,__LINE__)
void test_diff_parse__issue4672(void)
git_patch *patch;
git_buf buf = GIT_BUF_INIT;
- cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
+ cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION));
cl_git_pass(git_patch_from_buffers(&patch, a, strlen(a), NULL, b, strlen(b), NULL, &opts));
cl_git_pass(git_patch_to_buf(&buf, patch));
verify_patch_id(PATCH_SIMPLE_COMMIT, "06094b1948b878b7d9ff7560b4eae672a014b0ec");
}
+void test_diff_patchid__deleted_file(void)
+{
+ verify_patch_id(PATCH_DELETE_ORIGINAL, "d18507fe189f49c028b32c8c34e1ad98dd6a1aad");
+ verify_patch_id(PATCH_DELETED_FILE_2_HUNKS, "f31412498a17e6c3fbc635f2c5f9aa3ef4c1a9b7");
+}
+
+void test_diff_patchid__created_file(void)
+{
+ verify_patch_id(PATCH_ADD_ORIGINAL, "a7d39379308021465ae2ce65e338c048a3110db6");
+}
+
+void test_diff_patchid__binary_file(void)
+{
+ verify_patch_id(PATCH_ADD_BINARY_NOT_PRINTED, "2b31236b485faa30cf4dd33e4d6539829996739f");
+}
+
+void test_diff_patchid__renamed_file(void)
+{
+ verify_patch_id(PATCH_RENAME_EXACT, "4666d50cea4976f6f727448046d43461912058fd");
+ verify_patch_id(PATCH_RENAME_SIMILAR, "a795087575fcb940227be524488bedd6b3d3f438");
+}
+
+void test_diff_patchid__modechange(void)
+{
+ verify_patch_id(PATCH_MODECHANGE_UNCHANGED, "dbf3423ee98375ef1c72a79fbd29a049a2bae771");
+ verify_patch_id(PATCH_MODECHANGE_MODIFIED, "93aba696e1bbd2bbb73e3e3e62ed71f232137657");
+}
+
+void test_diff_patchid__shuffle_hunks(void)
+{
+ verify_patch_id(PATCH_DELETED_FILE_2_HUNKS_SHUFFLED, "f31412498a17e6c3fbc635f2c5f9aa3ef4c1a9b7");
+}
+
void test_diff_patchid__filename_with_spaces(void)
{
verify_patch_id(PATCH_APPEND_NO_NL, "f0ba05413beaef743b630e796153839462ee477a");
{
git_buf buf = GIT_BUF_INIT;
const char *stat =
- " binary.bin | Bin 3 -> 0 bytes\n"
+ " binary.bin | Bin 3 -> 5 bytes\n"
" 1 file changed, 0 insertions(+), 0 deletions(-)\n";
- /* TODO: Actually 0 bytes here should be 5!. Seems like we don't load the new content for binary files? */
diff_stats_from_commit_oid(
&_stats, "8d7523f6fcb2404257889abe0d96f093d9f524f9", false);
cl_assert_equal_s(stat, git_buf_cstr(&buf));
git_buf_dispose(&buf);
}
+
+void test_diff_stats__new_file(void)
+{
+ git_diff *diff;
+ git_buf buf = GIT_BUF_INIT;
+
+ const char *input =
+ "---\n"
+ " Gurjeet Singh | 1 +\n"
+ " 1 file changed, 1 insertion(+)\n"
+ " create mode 100644 Gurjeet Singh\n"
+ "\n"
+ "diff --git a/Gurjeet Singh b/Gurjeet Singh\n"
+ "new file mode 100644\n"
+ "index 0000000..6d0ecfd\n"
+ "--- /dev/null\n"
+ "+++ b/Gurjeet Singh \n"
+ "@@ -0,0 +1 @@\n"
+ "+I'm about to try git send-email\n"
+ "-- \n"
+ "2.21.0\n";
+
+ const char *stat =
+ " Gurjeet Singh | 1 +\n"
+ " 1 file changed, 1 insertion(+)\n"
+ " create mode 100644 Gurjeet Singh\n";
+
+ cl_git_pass(git_diff_from_buffer(&diff, input, strlen(input)));
+ cl_git_pass(git_diff_get_stats(&_stats, diff));
+ cl_git_pass(git_diff_stats_to_buf(&buf, _stats, GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY, 0));
+ cl_assert_equal_s(stat, git_buf_cstr(&buf));
+
+ git_buf_dispose(&buf);
+ git_diff_free(diff);
+}
#define get_buf_ptr(buf) ((buf)->asize ? (buf)->ptr : NULL)
static void check_diff_patches_at_line(
- git_diff *diff, const char **expected, const char *file, int line)
+ git_diff *diff, const char **expected,
+ const char *file, const char *func, int line)
{
const git_diff_delta *delta;
git_patch *patch = NULL;
cl_assert((delta = git_patch_get_delta(patch)) != NULL);
if (delta->status == GIT_DELTA_UNMODIFIED) {
- cl_assert_at_line(expected[d] == NULL, file, line);
+ cl_assert_at_line(expected[d] == NULL, file, func, line);
continue;
}
if (expected[d] && !strcmp(expected[d], "<SKIP>"))
continue;
if (expected[d] && !strcmp(expected[d], "<UNTRACKED>")) {
- cl_assert_at_line(delta->status == GIT_DELTA_UNTRACKED, file, line);
+ cl_assert_at_line(delta->status == GIT_DELTA_UNTRACKED, file, func, line);
continue;
}
if (expected[d] && !strcmp(expected[d], "<END>")) {
cl_git_pass(git_patch_to_buf(&buf, patch));
- cl_assert_at_line(!strcmp(expected[d], "<END>"), file, line);
+ cl_assert_at_line(!strcmp(expected[d], "<END>"), file, func, line);
}
cl_git_pass(git_patch_to_buf(&buf, patch));
clar__assert_equal(
- file, line, "expected diff did not match actual diff", 1,
+ file, func, line, "expected diff did not match actual diff", 1,
"%s", expected[d], get_buf_ptr(&buf));
git_buf_dispose(&buf);
}
- cl_assert_at_line(expected[d] && !strcmp(expected[d], "<END>"), file, line);
+ cl_assert_at_line(expected[d] && !strcmp(expected[d], "<END>"), file, func, line);
}
#define check_diff_patches(diff, exp) \
- check_diff_patches_at_line(diff, exp, __FILE__, __LINE__)
+ check_diff_patches_at_line(diff, exp, __FILE__, __func__, __LINE__)
void test_diff_submodules__unmodified_submodule(void)
{
void test_diff_tree__initialize(void)
{
- cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
+ cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION));
memset(&expect, 0, sizeof(expect));
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
- cl_git_pass(git_diff_foreach(diff,
+ cl_git_pass(git_diff_foreach(diff,
diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
cl_assert_equal_i(2, expect.files);
cl_assert_equal_i(7, expect.line_adds);
cl_assert_equal_i(15, expect.line_dels);
}
+
+void test_diff_tree__diff_tree_with_empty_dir_entry_succeeds(void)
+{
+ const char *content = "This is a blob\n";
+ const git_diff_delta *delta;
+ git_oid empty_tree, invalid_tree, blob;
+ git_buf patch = GIT_BUF_INIT;
+ git_treebuilder *builder;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(git_blob_create_from_buffer(&blob, g_repo, content, strlen(content)));
+ cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
+ cl_git_pass(git_treebuilder_write(&empty_tree, builder));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "empty_tree", &empty_tree, GIT_FILEMODE_TREE));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "blob", &blob, GIT_FILEMODE_BLOB));
+ cl_git_pass(git_treebuilder_write(&invalid_tree, builder));
+
+ cl_git_pass(git_tree_lookup(&a, g_repo, &empty_tree));
+ cl_git_pass(git_tree_lookup(&b, g_repo, &invalid_tree));
+ cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
+
+ cl_git_pass(git_diff_foreach(diff,
+ diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
+ cl_assert_equal_i(1, expect.files);
+ cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]);
+ cl_assert_equal_i(1, expect.hunks);
+ cl_assert_equal_i(1, expect.lines);
+ cl_assert_equal_i(0, expect.line_ctxt);
+ cl_assert_equal_i(1, expect.line_adds);
+ cl_assert_equal_i(0, expect.line_dels);
+
+ cl_git_pass(git_diff_to_buf(&patch, diff, GIT_DIFF_FORMAT_PATCH));
+ cl_assert_equal_s(patch.ptr,
+ "diff --git a/blob b/blob\n"
+ "new file mode 100644\n"
+ "index 0000000..bbf2e80\n"
+ "--- /dev/null\n"
+ "+++ b/blob\n"
+ "@@ -0,0 +1 @@\n"
+ "+This is a blob\n");
+
+ cl_assert_equal_i(git_diff_num_deltas(diff), 1);
+ delta = git_diff_get_delta(diff, 0);
+ cl_assert_equal_s(delta->new_file.path, "blob");
+
+ git_treebuilder_free(builder);
+ git_buf_dispose(&patch);
+}
git_buf b = GIT_BUF_INIT;
int i;
git_buf data[10] = {
- { "1234567890", 0, 0 }, /* 0 - all ascii text control */
- { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 0 }, /* 1 - UTF-8 multibyte text */
- { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 0 }, /* 2 - UTF-8 with BOM */
+ { "1234567890", 0, 10 }, /* 0 - all ascii text control */
+ { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 14 }, /* 1 - UTF-8 multibyte text */
+ { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 16 }, /* 2 - UTF-8 with BOM */
{ STR999Z, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */
{ STR3999Z, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */
{ STR4000 STR3999Z "x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */
g_repo = cl_git_sandbox_init("unsymlinked.git");
- cl_git_pass(git_repository__cvar(&symlinks, g_repo, GIT_CVAR_SYMLINKS));
+ cl_git_pass(git_repository__configmap_lookup(&symlinks, g_repo, GIT_CONFIGMAP_SYMLINKS));
if (symlinks)
cl_skip();
git_tree_free(tree);
git_vector_free(&pathlist);
}
+
+void test_diff_workdir__order(void)
+{
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_buf patch = GIT_BUF_INIT;
+ git_oid tree_oid, blob_oid;
+ git_treebuilder *builder;
+ git_tree *tree;
+ git_diff *diff;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ /* Build tree with a single file "abc.txt" */
+ cl_git_pass(git_blob_create_from_buffer(&blob_oid, g_repo, "foo\n", 4));
+ cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "abc.txt", &blob_oid, GIT_FILEMODE_BLOB));
+ cl_git_pass(git_treebuilder_write(&tree_oid, builder));
+ cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
+
+ /* Create a directory that sorts before and one that sorts after "abc.txt" */
+ cl_git_mkfile("empty_standard_repo/abc.txt", "bar\n");
+ cl_must_pass(p_mkdir("empty_standard_repo/abb", 0777));
+ cl_must_pass(p_mkdir("empty_standard_repo/abd", 0777));
+
+ opts.flags = GIT_DIFF_INCLUDE_UNTRACKED;
+ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts));
+
+ cl_assert_equal_i(1, git_diff_num_deltas(diff));
+ cl_git_pass(git_diff_to_buf(&patch, diff, GIT_DIFF_FORMAT_PATCH));
+ cl_assert_equal_s(patch.ptr,
+ "diff --git a/abc.txt b/abc.txt\n"
+ "index 257cc56..5716ca5 100644\n"
+ "--- a/abc.txt\n"
+ "+++ b/abc.txt\n"
+ "@@ -1 +1 @@\n"
+ "-foo\n"
+ "+bar\n");
+
+ git_treebuilder_free(builder);
+ git_buf_dispose(&patch);
+ git_diff_free(diff);
+ git_tree_free(tree);
+}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "fetchhead.h"
#include "fetchhead_data.h"
typedef struct {
git_vector *fetchhead_vector;
size_t idx;
-} fetchhead_ref_cb_data;
+} fetchhead_ref_cb_data;
static int fetchhead_ref_cb(const char *name, const char *url,
const git_oid *oid, unsigned int is_merge, void *payload)
git_remote_free(remote);
git_buf_dispose(&path);
}
+
+void test_fetchhead_nonetwork__credentials_are_stripped(void)
+{
+ git_fetchhead_ref *ref;
+ git_oid oid;
+
+ cl_git_pass(git_oid_fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0"));
+ cl_git_pass(git_fetchhead_ref_create(&ref, &oid, 0,
+ "refs/tags/commit_tree", "http://foo:bar@github.com/libgit2/TestGitRepository"));
+ cl_assert_equal_s(ref->remote_url, "http://github.com/libgit2/TestGitRepository");
+ git_fetchhead_ref_free(ref);
+
+ cl_git_pass(git_oid_fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0"));
+ cl_git_pass(git_fetchhead_ref_create(&ref, &oid, 0,
+ "refs/tags/commit_tree", "https://foo:bar@github.com/libgit2/TestGitRepository"));
+ cl_assert_equal_s(ref->remote_url, "https://github.com/libgit2/TestGitRepository");
+ git_fetchhead_ref_free(ref);
+}
--- /dev/null
+#include "clar_libgit2.h"
+#include "crlf.h"
+
+static git_repository *g_repo = NULL;
+static git_blob_filter_options filter_opts = GIT_BLOB_FILTER_OPTIONS_INIT;
+
+void test_filter_bare__initialize(void)
+{
+ cl_fixture_sandbox("crlf.git");
+ cl_git_pass(git_repository_open(&g_repo, "crlf.git"));
+
+ filter_opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
+ filter_opts.flags |= GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD;
+}
+
+void test_filter_bare__cleanup(void)
+{
+ git_repository_free(g_repo);
+ cl_fixture_cleanup("crlf.git");
+}
+
+void test_filter_bare__all_crlf(void)
+{
+ git_blob *blob;
+ git_buf buf = { 0 };
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "a9a2e89")); /* all-crlf */
+
+ cl_assert_equal_s(ALL_CRLF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &filter_opts));
+
+ cl_assert_equal_s(ALL_CRLF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &filter_opts));
+
+ /* in this case, raw content has crlf in it already */
+ cl_assert_equal_s(ALL_CRLF_TEXT_AS_CRLF, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &filter_opts));
+
+ /* we never convert CRLF -> LF on platforms that have LF */
+ cl_assert_equal_s(ALL_CRLF_TEXT_AS_CRLF, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.txt", &filter_opts));
+
+ /* in this case, raw content has crlf in it already */
+ cl_assert_equal_s(ALL_CRLF_TEXT_AS_CRLF, buf.ptr);
+
+ git_buf_dispose(&buf);
+ git_blob_free(blob);
+}
+
+void test_filter_bare__from_lf(void)
+{
+ git_blob *blob;
+ git_buf buf = { 0 };
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "799770d")); /* all-lf */
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &filter_opts));
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &filter_opts));
+
+ /* in this case, raw content has crlf in it already */
+ cl_assert_equal_s(ALL_LF_TEXT_AS_CRLF, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &filter_opts));
+
+ /* we never convert CRLF -> LF on platforms that have LF */
+ cl_assert_equal_s(ALL_LF_TEXT_AS_LF, buf.ptr);
+
+ git_buf_dispose(&buf);
+ git_blob_free(blob);
+}
+
+void test_filter_bare__nested_attributes(void)
+{
+ git_blob *blob;
+ git_buf buf = { 0 };
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "799770d")); /* all-lf */
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "raw/file.bin", &filter_opts));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "raw/file.crlf", &filter_opts));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "raw/file.lf", &filter_opts));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ git_buf_dispose(&buf);
+ git_blob_free(blob);
+}
+
+void test_filter_bare__sanitizes(void)
+{
+ git_blob *blob;
+ git_buf buf = GIT_BUF_INIT;
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "e69de29")); /* zero-byte */
+
+ cl_assert_equal_i(0, git_blob_rawsize(blob));
+ cl_assert_equal_s("", git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &filter_opts));
+ cl_assert_equal_sz(0, buf.size);
+ cl_assert_equal_s("", buf.ptr);
+ git_buf_dispose(&buf);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &filter_opts));
+ cl_assert_equal_sz(0, buf.size);
+ cl_assert_equal_s("", buf.ptr);
+ git_buf_dispose(&buf);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &filter_opts));
+ cl_assert_equal_sz(0, buf.size);
+ cl_assert_equal_s("", buf.ptr);
+ git_buf_dispose(&buf);
+
+ git_blob_free(blob);
+}
+
cl_assert_equal_s(ALL_CRLF_TEXT_RAW, git_blob_rawcontent(blob));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "file.bin", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", NULL));
cl_assert_equal_s(ALL_CRLF_TEXT_RAW, buf.ptr);
- cl_git_pass(git_blob_filtered_content(&buf, blob, "file.crlf", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", NULL));
/* in this case, raw content has crlf in it already */
cl_assert_equal_s(ALL_CRLF_TEXT_AS_CRLF, buf.ptr);
- cl_git_pass(git_blob_filtered_content(&buf, blob, "file.lf", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", NULL));
/* we never convert CRLF -> LF on platforms that have LF */
cl_assert_equal_s(ALL_CRLF_TEXT_AS_CRLF, buf.ptr);
git_blob_free(blob);
}
+void test_filter_blob__from_lf(void)
+{
+ git_blob *blob;
+ git_buf buf = { 0 };
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "799770d")); /* all-lf */
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", NULL));
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", NULL));
+
+ /* in this case, raw content has crlf in it already */
+ cl_assert_equal_s(ALL_LF_TEXT_AS_CRLF, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", NULL));
+
+ /* we never convert CRLF -> LF on platforms that have LF */
+ cl_assert_equal_s(ALL_LF_TEXT_AS_LF, buf.ptr);
+
+ git_buf_dispose(&buf);
+ git_blob_free(blob);
+}
+
void test_filter_blob__sanitizes(void)
{
git_blob *blob;
cl_assert_equal_s("", git_blob_rawcontent(blob));
memset(&buf, 0, sizeof(git_buf));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "file.bin", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", NULL));
cl_assert_equal_sz(0, buf.size);
cl_assert_equal_s("", buf.ptr);
git_buf_dispose(&buf);
memset(&buf, 0, sizeof(git_buf));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "file.crlf", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", NULL));
cl_assert_equal_sz(0, buf.size);
cl_assert_equal_s("", buf.ptr);
git_buf_dispose(&buf);
memset(&buf, 0, sizeof(git_buf));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "file.lf", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", NULL));
cl_assert_equal_sz(0, buf.size);
cl_assert_equal_s("", buf.ptr);
git_buf_dispose(&buf);
git_buf buf = { 0 };
cl_git_mkfile("crlf/test.ident", "Some text\n$Id$\nGoes there\n");
- cl_git_pass(git_blob_create_fromworkdir(&id, g_repo, "test.ident"));
+ cl_git_pass(git_blob_create_from_workdir(&id, g_repo, "test.ident"));
cl_git_pass(git_blob_lookup(&blob, g_repo, &id));
cl_assert_equal_s(
"Some text\n$Id$\nGoes there\n", git_blob_rawcontent(blob));
git_blob_free(blob);
cl_git_mkfile("crlf/test.ident", "Some text\n$Id: Any old just you want$\nGoes there\n");
- cl_git_pass(git_blob_create_fromworkdir(&id, g_repo, "test.ident"));
+ cl_git_pass(git_blob_create_from_workdir(&id, g_repo, "test.ident"));
cl_git_pass(git_blob_lookup(&blob, g_repo, &id));
cl_assert_equal_s(
"Some text\n$Id$\nGoes there\n", git_blob_rawcontent(blob));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "filter.bin", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "filter.bin", NULL));
cl_assert_equal_s(
"Some text\n$Id$\nGoes there\n", buf.ptr);
- cl_git_pass(git_blob_filtered_content(&buf, blob, "filter.identcrlf", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "filter.identcrlf", NULL));
cl_assert_equal_s(
"Some text\r\n$Id: 3164f585d548ac68027d22b104f2d8100b2b6845 $\r\nGoes there\r\n", buf.ptr);
- cl_git_pass(git_blob_filtered_content(&buf, blob, "filter.identlf", 1));
+ cl_git_pass(git_blob_filter(&buf, blob, "filter.identlf", NULL));
cl_assert_equal_s(
"Some text\n$Id: 3164f585d548ac68027d22b104f2d8100b2b6845 $\nGoes there\n", buf.ptr);
& git_index_get_bypath(index, "hero.1.rev-ident", 0)->id));
cl_assert_equal_s(
"\n!nuf evaH\n$dI$\ntset a si sihT", git_blob_rawcontent(blob));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.1.rev-ident", 0));
+ cl_git_pass(git_blob_filter(&buf, blob, "hero.1.rev-ident", NULL));
/* no expansion because id was reversed at checkin and now at ident
* time, reverse is not applied yet */
cl_assert_equal_s(
& git_index_get_bypath(index, "hero.2.rev-ident", 0)->id));
cl_assert_equal_s(
"\n!yzarC\n$Id$\ntset rehtonA", git_blob_rawcontent(blob));
- cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.2.rev-ident", 0));
+ cl_git_pass(git_blob_filter(&buf, blob, "hero.2.rev-ident", NULL));
/* expansion because reverse was applied at checkin and at ident time,
* reverse is not applied yet */
cl_assert_equal_s(
git_buf out = { 0 };
cl_git_mkfile("crlf/identtest", data);
- cl_git_pass(git_blob_create_fromworkdir(&id, g_repo, "identtest"));
+ cl_git_pass(git_blob_create_from_workdir(&id, g_repo, "identtest"));
cl_git_pass(git_blob_lookup(&blob, g_repo, &id));
cl_git_pass(git_filter_list_apply_to_blob(&out, fl, blob));
--- /dev/null
+#include "clar_libgit2.h"
+#include "crlf.h"
+#include "path.h"
+
+static git_repository *g_repo = NULL;
+static git_buf system_attr_path = GIT_BUF_INIT;
+
+void test_filter_systemattrs__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("crlf");
+ cl_must_pass(p_unlink("crlf/.gitattributes"));
+
+ cl_git_pass(git_libgit2_opts(
+ GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, &system_attr_path));
+ cl_git_pass(git_buf_joinpath(&system_attr_path,
+ system_attr_path.ptr, "gitattributes"));
+
+ cl_git_mkfile(system_attr_path.ptr,
+ "*.txt text\n"
+ "*.bin binary\n"
+ "*.crlf text eol=crlf\n"
+ "*.lf text eol=lf\n");
+}
+
+void test_filter_systemattrs__cleanup(void)
+{
+ cl_must_pass(p_unlink(system_attr_path.ptr));
+ git_buf_dispose(&system_attr_path);
+
+ cl_git_sandbox_cleanup();
+}
+
+void test_filter_systemattrs__reads_system_attributes(void)
+{
+ git_blob *blob;
+ git_buf buf = { 0 };
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "799770d")); /* all-lf */
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", NULL));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", NULL));
+ cl_assert_equal_s(ALL_LF_TEXT_AS_CRLF, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", NULL));
+ cl_assert_equal_s(ALL_LF_TEXT_AS_LF, buf.ptr);
+
+ git_buf_dispose(&buf);
+ git_blob_free(blob);
+}
+
+void test_filter_systemattrs__disables_system_attributes(void)
+{
+ git_blob *blob;
+ git_buf buf = { 0 };
+ git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
+
+ opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&blob, g_repo, "799770d")); /* all-lf */
+
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &opts));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ /* No attributes mean these are all treated literally */
+ cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &opts));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &opts));
+ cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
+
+ git_buf_dispose(&buf);
+ git_blob_free(blob);
+}
def render(self):
out = "\n".join("extern %s;" % cb['declaration'] for cb in self.module.callbacks) + "\n"
- if self.module.initialize:
- out += "extern %s;\n" % self.module.initialize['declaration']
+ for initializer in self.module.initializers:
+ out += "extern %s;\n" % initializer['declaration']
if self.module.cleanup:
out += "extern %s;\n" % self.module.cleanup['declaration']
class InfoTemplate(Template):
def render(self):
- return Template(
+ templates = []
+
+ initializers = self.module.initializers
+ if len(initializers) == 0:
+ initializers = [ None ]
+
+ for initializer in initializers:
+ name = self.module.clean_name()
+ if initializer and initializer['short_name'].startswith('initialize_'):
+ variant = initializer['short_name'][len('initialize_'):]
+ name += " (%s)" % variant.replace('_', ' ')
+
+ template = Template(
r"""
{
"${clean_name}",
${cleanup},
${cb_ptr}, ${cb_count}, ${enabled}
}"""
- ).substitute(
- clean_name = self.module.clean_name(),
- initialize = self._render_callback(self.module.initialize),
- cleanup = self._render_callback(self.module.cleanup),
- cb_ptr = "_clar_cb_%s" % self.module.name,
- cb_count = len(self.module.callbacks),
- enabled = int(self.module.enabled)
- )
+ ).substitute(
+ clean_name = name,
+ initialize = self._render_callback(initializer),
+ cleanup = self._render_callback(self.module.cleanup),
+ cb_ptr = "_clar_cb_%s" % self.module.name,
+ cb_count = len(self.module.callbacks),
+ enabled = int(self.module.enabled)
+ )
+ templates.append(template)
+
+ return ','.join(templates)
def __init__(self, name):
self.name = name
regex = re.compile(TEST_FUNC_REGEX % self.name, re.MULTILINE)
self.callbacks = []
- self.initialize = None
+ self.initializers = []
self.cleanup = None
for (declaration, symbol, short_name) in regex.findall(contents):
"symbol" : symbol
}
- if short_name == 'initialize':
- self.initialize = data
+ if short_name.startswith('initialize'):
+ self.initializers.append(data)
elif short_name == 'cleanup':
self.cleanup = data
else:
module.modified = True
def suite_count(self):
- return len(self.modules)
+ return sum(max(1, len(m.initializers)) for m in self.modules.values())
def callback_count(self):
return sum(len(module.callbacks) for module in self.modules.values())
--- /dev/null
+#include "clar_libgit2.h"
+
+static git_repository *_repo;
+static git_commit *commit;
+static size_t ahead;
+static size_t behind;
+
+void test_graph_ahead_behind__initialize(void)
+{
+ git_oid oid;
+ cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git")));
+
+ cl_git_pass(git_oid_fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
+ cl_git_pass(git_commit_lookup(&commit, _repo, &oid));
+}
+
+void test_graph_ahead_behind__cleanup(void)
+{
+ git_commit_free(commit);
+ commit = NULL;
+
+ git_repository_free(_repo);
+ _repo = NULL;
+}
+
+void test_graph_ahead_behind__returns_correct_result(void)
+{
+ git_oid oid;
+ git_oid oid2;
+ git_commit *other;
+
+ cl_git_pass(git_oid_fromstr(&oid, "e90810b8df3e80c413d903f631643c716887138d"));
+ cl_git_pass(git_oid_fromstr(&oid2, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
+
+ cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, &oid, &oid2));
+ cl_assert_equal_sz(2, ahead);
+ cl_assert_equal_sz(6, behind);
+
+ cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, git_commit_id(commit), git_commit_id(commit)));
+ cl_assert_equal_sz(ahead, behind);
+ cl_git_pass(git_commit_nth_gen_ancestor(&other, commit, 1));
+
+ cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, git_commit_id(commit), git_commit_id(other)));
+ cl_assert_equal_sz(ahead, behind + 2);
+ cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, git_commit_id(other), git_commit_id(commit)));
+ cl_assert_equal_sz(ahead + 2, behind);
+
+ git_commit_free(other);
+
+ cl_git_pass(git_commit_nth_gen_ancestor(&other, commit, 3));
+
+ cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, git_commit_id(commit), git_commit_id(other)));
+ cl_assert_equal_sz(ahead, behind + 4);
+ cl_git_pass(git_graph_ahead_behind(&ahead, &behind, _repo, git_commit_id(other), git_commit_id(commit)));
+ cl_assert_equal_sz(ahead + 4, behind);
+
+ git_commit_free(other);
+}
--- /dev/null
+#include "clar_libgit2.h"
+#include "posix.h"
+#include "path.h"
+#include "futils.h"
+
+static git_repository *g_repo = NULL;
+
+void test_ignore_path__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("attr");
+}
+
+void test_ignore_path__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ g_repo = NULL;
+}
+
+static void assert_is_ignored_(
+ bool expected, const char *filepath,
+ const char *file, const char *func, int line)
+{
+ int is_ignored = 0;
+
+ cl_git_expect(
+ git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), 0, file, func, line);
+
+ clar__assert_equal(
+ file, func, line, "expected != is_ignored", 1, "%d",
+ (int)(expected != 0), (int)(is_ignored != 0));
+}
+#define assert_is_ignored(expected, filepath) \
+ assert_is_ignored_(expected, filepath, __FILE__, __func__, __LINE__)
+
+void test_ignore_path__honor_temporary_rules(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "/NewFolder\n/NewFolder/NewFolder");
+
+ assert_is_ignored(false, "File.txt");
+ assert_is_ignored(true, "NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
+}
+
+void test_ignore_path__allow_root(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "/");
+
+ assert_is_ignored(false, "File.txt");
+ assert_is_ignored(false, "NewFolder");
+ assert_is_ignored(false, "NewFolder/NewFolder");
+ assert_is_ignored(false, "NewFolder/NewFolder/File.txt");
+}
+
+void test_ignore_path__ignore_space(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder \n/NewFolder/NewFolder");
+
+ assert_is_ignored(false, "File.txt");
+ assert_is_ignored(true, "NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
+}
+
+void test_ignore_path__intermittent_space(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "foo bar\n");
+
+ assert_is_ignored(false, "foo");
+ assert_is_ignored(false, "bar");
+ assert_is_ignored(true, "foo bar");
+}
+
+void test_ignore_path__trailing_space(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "foo \n"
+ "bar \n"
+ );
+
+ assert_is_ignored(true, "foo");
+ assert_is_ignored(false, "foo ");
+ assert_is_ignored(true, "bar");
+ assert_is_ignored(false, "bar ");
+ assert_is_ignored(false, "bar ");
+}
+
+void test_ignore_path__escaped_trailing_spaces(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "foo\\ \n"
+ "bar\\ \\ \n"
+ "baz \\ \n"
+ "qux\\ \n"
+ );
+
+ assert_is_ignored(false, "foo");
+ assert_is_ignored(true, "foo ");
+ assert_is_ignored(false, "bar");
+ assert_is_ignored(false, "bar ");
+ assert_is_ignored(true, "bar ");
+ assert_is_ignored(true, "baz ");
+ assert_is_ignored(false, "baz ");
+ assert_is_ignored(true, "qux ");
+ assert_is_ignored(false, "qux");
+ assert_is_ignored(false, "qux ");
+}
+
+void test_ignore_path__ignore_dir(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "dir/\n");
+
+ assert_is_ignored(true, "dir");
+ assert_is_ignored(true, "dir/file");
+}
+
+void test_ignore_path__ignore_dir_with_trailing_space(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "dir/ \n");
+
+ assert_is_ignored(true, "dir");
+ assert_is_ignored(true, "dir/file");
+}
+
+void test_ignore_path__ignore_root(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder");
+
+ assert_is_ignored(false, "File.txt");
+ assert_is_ignored(true, "NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
+}
+
+void test_ignore_path__full_paths(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "Folder/*/Contained");
+
+ assert_is_ignored(true, "Folder/Middle/Contained");
+ assert_is_ignored(false, "Folder/Middle/More/More/Contained");
+
+ cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained");
+
+ assert_is_ignored(true, "Folder/Middle/Contained");
+ assert_is_ignored(true, "Folder/Middle/More/More/Contained");
+
+ cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained/*/Child");
+
+ assert_is_ignored(true, "Folder/Middle/Contained/Happy/Child");
+ assert_is_ignored(false, "Folder/Middle/Contained/Not/Happy/Child");
+ assert_is_ignored(true, "Folder/Middle/More/More/Contained/Happy/Child");
+ assert_is_ignored(false, "Folder/Middle/More/More/Contained/Not/Happy/Child");
+}
+
+void test_ignore_path__more_starstar_cases(void)
+{
+ cl_must_pass(p_unlink("attr/.gitignore"));
+ cl_git_mkfile(
+ "attr/dir/.gitignore",
+ "sub/**/*.html\n");
+
+ assert_is_ignored(false, "aaa.html");
+ assert_is_ignored(false, "dir");
+ assert_is_ignored(false, "dir/sub");
+ assert_is_ignored(true, "dir/sub/sub2/aaa.html");
+ assert_is_ignored(true, "dir/sub/aaa.html");
+ assert_is_ignored(false, "dir/aaa.html");
+ assert_is_ignored(false, "sub");
+ assert_is_ignored(false, "sub/aaa.html");
+ assert_is_ignored(false, "sub/sub2/aaa.html");
+}
+
+void test_ignore_path__leading_stars(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "*/onestar\n"
+ "**/twostars\n"
+ "*/parent1/kid1/*\n"
+ "**/parent2/kid2/*\n");
+
+ assert_is_ignored(true, "dir1/onestar");
+ assert_is_ignored(true, "dir1/onestar/child"); /* in ignored dir */
+ assert_is_ignored(false, "dir1/dir2/onestar");
+
+ assert_is_ignored(true, "dir1/twostars");
+ assert_is_ignored(true, "dir1/twostars/child"); /* in ignored dir */
+ assert_is_ignored(true, "dir1/dir2/twostars");
+ assert_is_ignored(true, "dir1/dir2/twostars/child"); /* in ignored dir */
+ assert_is_ignored(true, "dir1/dir2/dir3/twostars");
+
+ assert_is_ignored(true, "dir1/parent1/kid1/file");
+ assert_is_ignored(true, "dir1/parent1/kid1/file/inside/parent");
+ assert_is_ignored(false, "dir1/dir2/parent1/kid1/file");
+ assert_is_ignored(false, "dir1/parent1/file");
+ assert_is_ignored(false, "dir1/kid1/file");
+
+ assert_is_ignored(true, "dir1/parent2/kid2/file");
+ assert_is_ignored(true, "dir1/parent2/kid2/file/inside/parent");
+ assert_is_ignored(true, "dir1/dir2/parent2/kid2/file");
+ assert_is_ignored(true, "dir1/dir2/dir3/parent2/kid2/file");
+ assert_is_ignored(false, "dir1/parent2/file");
+ assert_is_ignored(false, "dir1/kid2/file");
+}
+
+void test_ignore_path__globs_and_path_delimiters(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "foo/bar/**");
+ assert_is_ignored(true, "foo/bar/baz");
+ assert_is_ignored(true, "foo/bar/baz/quux");
+
+ cl_git_rewritefile("attr/.gitignore", "_*/");
+ assert_is_ignored(true, "sub/_test/a/file");
+ assert_is_ignored(false, "test_folder/file");
+ assert_is_ignored(true, "_test/file");
+ assert_is_ignored(true, "_test/a/file");
+
+ cl_git_rewritefile("attr/.gitignore", "**/_*/");
+ assert_is_ignored(true, "sub/_test/a/file");
+ assert_is_ignored(false, "test_folder/file");
+ assert_is_ignored(true, "_test/file");
+ assert_is_ignored(true, "_test/a/file");
+
+ cl_git_rewritefile("attr/.gitignore", "**/_*/foo/bar/*ux");
+
+ assert_is_ignored(true, "sub/_test/foo/bar/qux/file");
+ assert_is_ignored(true, "_test/foo/bar/qux/file");
+ assert_is_ignored(true, "_test/foo/bar/crux/file");
+ assert_is_ignored(false, "_test/foo/bar/code/file");
+}
+
+void test_ignore_path__globs_without_star(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "*.foo\n"
+ "**.bar\n"
+ );
+
+ assert_is_ignored(true, ".foo");
+ assert_is_ignored(true, "xyz.foo");
+ assert_is_ignored(true, ".bar");
+ assert_is_ignored(true, "x.bar");
+ assert_is_ignored(true, "xyz.bar");
+
+ assert_is_ignored(true, "test/.foo");
+ assert_is_ignored(true, "test/x.foo");
+ assert_is_ignored(true, "test/xyz.foo");
+ assert_is_ignored(true, "test/.bar");
+ assert_is_ignored(true, "test/x.bar");
+ assert_is_ignored(true, "test/xyz.bar");
+}
+
+void test_ignore_path__skip_gitignore_directory(void)
+{
+ cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder");
+ cl_must_pass(p_unlink("attr/.gitignore"));
+ cl_assert(!git_path_exists("attr/.gitignore"));
+ p_mkdir("attr/.gitignore", 0777);
+ cl_git_mkfile("attr/.gitignore/garbage.txt", "new_file\n");
+
+ assert_is_ignored(false, "File.txt");
+ assert_is_ignored(true, "NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder");
+ assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
+}
+
+void test_ignore_path__subdirectory_gitignore(void)
+{
+ cl_must_pass(p_unlink("attr/.gitignore"));
+ cl_assert(!git_path_exists("attr/.gitignore"));
+ cl_git_mkfile(
+ "attr/.gitignore",
+ "file1\n");
+ cl_git_mkfile(
+ "attr/dir/.gitignore",
+ "file2/\n");
+
+ assert_is_ignored(true, "file1");
+ assert_is_ignored(true, "dir/file1");
+ assert_is_ignored(true, "dir/file2/actual_file"); /* in ignored dir */
+ assert_is_ignored(false, "dir/file3");
+}
+
+void test_ignore_path__expand_tilde_to_homedir(void)
+{
+ git_config *cfg;
+
+ assert_is_ignored(false, "example.global_with_tilde");
+
+ cl_fake_home();
+
+ /* construct fake home with fake global excludes */
+ cl_git_mkfile("home/globalexclude", "# found me\n*.global_with_tilde\n");
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexclude"));
+ git_config_free(cfg);
+
+ git_attr_cache_flush(g_repo); /* must reset to pick up change */
+
+ assert_is_ignored(true, "example.global_with_tilde");
+
+ cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
+
+ cl_fake_home_cleanup(NULL);
+
+ git_attr_cache_flush(g_repo); /* must reset to pick up change */
+
+ assert_is_ignored(false, "example.global_with_tilde");
+}
+
+/* Ensure that the .gitignore in the subdirectory only affects
+ * items in the subdirectory. */
+void test_ignore_path__gitignore_in_subdir(void)
+{
+ cl_git_rmfile("attr/.gitignore");
+
+ cl_must_pass(p_mkdir("attr/dir1", 0777));
+ cl_must_pass(p_mkdir("attr/dir1/dir2", 0777));
+ cl_must_pass(p_mkdir("attr/dir1/dir2/dir3", 0777));
+
+ cl_git_mkfile("attr/dir1/dir2/dir3/.gitignore", "dir1/\ndir1/subdir/");
+
+ assert_is_ignored(false, "dir1/file");
+ assert_is_ignored(false, "dir1/dir2/file");
+ assert_is_ignored(false, "dir1/dir2/dir3/file");
+ assert_is_ignored(true, "dir1/dir2/dir3/dir1/file");
+ assert_is_ignored(true, "dir1/dir2/dir3/dir1/subdir/foo");
+
+ if (cl_repo_get_bool(g_repo, "core.ignorecase")) {
+ cl_git_mkfile("attr/dir1/dir2/dir3/.gitignore", "DiR1/\nDiR1/subdir/\n");
+
+ assert_is_ignored(false, "dir1/file");
+ assert_is_ignored(false, "dir1/dir2/file");
+ assert_is_ignored(false, "dir1/dir2/dir3/file");
+ assert_is_ignored(true, "dir1/dir2/dir3/dir1/file");
+ assert_is_ignored(true, "dir1/dir2/dir3/dir1/subdir/foo");
+ }
+}
+
+/* Ensure that files do not match folder cases */
+void test_ignore_path__dont_ignore_files_for_folder(void)
+{
+ cl_git_rmfile("attr/.gitignore");
+
+ cl_git_mkfile("attr/dir/.gitignore", "test/\n");
+
+ /* Create "test" as a file; ensure it is not ignored. */
+ cl_git_mkfile("attr/dir/test", "This is a file.");
+
+ assert_is_ignored(false, "dir/test");
+ if (cl_repo_get_bool(g_repo, "core.ignorecase"))
+ assert_is_ignored(false, "dir/TeSt");
+
+ /* Create "test" as a directory; ensure it is ignored. */
+ cl_git_rmfile("attr/dir/test");
+ cl_must_pass(p_mkdir("attr/dir/test", 0777));
+
+ assert_is_ignored(true, "dir/test");
+ if (cl_repo_get_bool(g_repo, "core.ignorecase"))
+ assert_is_ignored(true, "dir/TeSt");
+
+ /* Remove "test" entirely; ensure it is not ignored.
+ * (As it doesn't exist, it is not a directory.)
+ */
+ cl_must_pass(p_rmdir("attr/dir/test"));
+
+ assert_is_ignored(false, "dir/test");
+ if (cl_repo_get_bool(g_repo, "core.ignorecase"))
+ assert_is_ignored(false, "dir/TeSt");
+}
+
+void test_ignore_path__symlink_to_outside(void)
+{
+#ifdef GIT_WIN32
+ cl_skip();
+#endif
+
+ cl_git_rewritefile("attr/.gitignore", "symlink\n");
+ cl_git_mkfile("target", "target");
+ cl_git_pass(p_symlink("../target", "attr/symlink"));
+ assert_is_ignored(true, "symlink");
+ assert_is_ignored(true, "lala/../symlink");
+}
+
+void test_ignore_path__test(void)
+{
+ cl_git_rewritefile("attr/.gitignore",
+ "/*/\n"
+ "!/src\n");
+ assert_is_ignored(false, "src/foo.c");
+ assert_is_ignored(false, "src/foo/foo.c");
+ assert_is_ignored(false, "README.md");
+ assert_is_ignored(true, "dist/foo.o");
+ assert_is_ignored(true, "bin/foo");
+}
+
+void test_ignore_path__unignore_dir_succeeds(void)
+{
+ cl_git_rewritefile("attr/.gitignore",
+ "*.c\n"
+ "!src/*.c\n");
+ assert_is_ignored(false, "src/foo.c");
+ assert_is_ignored(true, "src/foo/foo.c");
+}
+
+void test_ignore_path__case_insensitive_unignores_previous_rule(void)
+{
+ git_config *cfg;
+
+ cl_git_rewritefile("attr/.gitignore",
+ "/case\n"
+ "!/Case/\n");
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true));
+
+ cl_must_pass(p_mkdir("attr/case", 0755));
+ cl_git_mkfile("attr/case/file", "content");
+
+ assert_is_ignored(false, "case/file");
+}
+
+void test_ignore_path__case_sensitive_unignore_does_nothing(void)
+{
+ git_config *cfg;
+
+ cl_git_rewritefile("attr/.gitignore",
+ "/case\n"
+ "!/Case/\n");
+
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false));
+
+ cl_must_pass(p_mkdir("attr/case", 0755));
+ cl_git_mkfile("attr/case/file", "content");
+
+ assert_is_ignored(true, "case/file");
+}
+
+void test_ignore_path__ignored_subdirfiles_with_subdir_rule(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "dir/*\n"
+ "!dir/sub1/sub2/**\n");
+
+ assert_is_ignored(true, "dir/a.test");
+ assert_is_ignored(true, "dir/sub1/a.test");
+ assert_is_ignored(true, "dir/sub1/sub2");
+}
+
+void test_ignore_path__ignored_subdirfiles_with_negations(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "dir/*\n"
+ "!dir/a.test\n");
+
+ assert_is_ignored(false, "dir/a.test");
+ assert_is_ignored(true, "dir/b.test");
+ assert_is_ignored(true, "dir/sub1/c.test");
+}
+
+void test_ignore_path__negative_directory_rules_only_match_directories(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "*\n"
+ "!/**/\n"
+ "!*.keep\n"
+ "!.gitignore\n"
+ );
+
+ assert_is_ignored(true, "src");
+ assert_is_ignored(true, "src/A");
+ assert_is_ignored(false, "src/");
+ assert_is_ignored(false, "src/A.keep");
+ assert_is_ignored(false, ".gitignore");
+}
+
+void test_ignore_path__escaped_character(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "\\c\n");
+ assert_is_ignored(true, "c");
+ assert_is_ignored(false, "\\c");
+}
+
+void test_ignore_path__escaped_newline(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "\\\nnewline\n"
+ );
+
+ assert_is_ignored(true, "\nnewline");
+}
+
+void test_ignore_path__escaped_glob(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "\\*\n");
+ assert_is_ignored(true, "*");
+ assert_is_ignored(false, "foo");
+}
+
+void test_ignore_path__escaped_comments(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "#foo\n"
+ "\\#bar\n"
+ "\\##baz\n"
+ "\\#\\\\#qux\n"
+ );
+
+ assert_is_ignored(false, "#foo");
+ assert_is_ignored(true, "#bar");
+ assert_is_ignored(false, "\\#bar");
+ assert_is_ignored(true, "##baz");
+ assert_is_ignored(false, "\\##baz");
+ assert_is_ignored(true, "#\\#qux");
+ assert_is_ignored(false, "##qux");
+ assert_is_ignored(false, "\\##qux");
+}
+
+void test_ignore_path__escaped_slash(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "\\\\\n"
+ "\\\\preceding\n"
+ "inter\\\\mittent\n"
+ "trailing\\\\\n"
+ );
+
+#ifndef GIT_WIN32
+ assert_is_ignored(true, "\\");
+ assert_is_ignored(true, "\\preceding");
+#endif
+ assert_is_ignored(true, "inter\\mittent");
+ assert_is_ignored(true, "trailing\\");
+}
+
+void test_ignore_path__escaped_space(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "foo\\\\ \n"
+ "bar\\\\\\ \n");
+ assert_is_ignored(true, "foo\\");
+ assert_is_ignored(false, "foo\\ ");
+ assert_is_ignored(false, "foo\\\\ ");
+ assert_is_ignored(false, "foo\\\\");
+ assert_is_ignored(true, "bar\\ ");
+ assert_is_ignored(false, "bar\\\\");
+ assert_is_ignored(false, "bar\\\\ ");
+ assert_is_ignored(false, "bar\\\\\\");
+ assert_is_ignored(false, "bar\\\\\\ ");
+}
+
+void test_ignore_path__invalid_pattern(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "[");
+ assert_is_ignored(false, "[f");
+ assert_is_ignored(false, "f");
+}
+
+void test_ignore_path__negative_prefix_rule(void)
+{
+ cl_git_rewritefile("attr/.gitignore", "ff*\n!f\n");
+ assert_is_ignored(true, "fff");
+ assert_is_ignored(true, "ff");
+ assert_is_ignored(false, "f");
+}
--- /dev/null
+#include "clar_libgit2.h"
+#include "futils.h"
+#include "git2/attr.h"
+#include "ignore.h"
+#include "attr.h"
+#include "status/status_helpers.h"
+
+static git_repository *g_repo = NULL;
+
+void test_ignore_status__initialize(void)
+{
+}
+
+void test_ignore_status__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+static void assert_ignored_(
+ bool expected, const char *filepath,
+ const char *file, const char *func, int line)
+{
+ int is_ignored = 0;
+ cl_git_expect(
+ git_status_should_ignore(&is_ignored, g_repo, filepath), 0, file, func, line);
+ clar__assert(
+ (expected != 0) == (is_ignored != 0),
+ file, func, line, "expected != is_ignored", filepath, 1);
+}
+#define assert_ignored(expected, filepath) \
+ assert_ignored_(expected, filepath, __FILE__, __func__, __LINE__)
+#define assert_is_ignored(filepath) \
+ assert_ignored_(true, filepath, __FILE__, __func__, __LINE__)
+#define refute_is_ignored(filepath) \
+ assert_ignored_(false, filepath, __FILE__, __func__, __LINE__)
+
+void test_ignore_status__0(void)
+{
+ struct {
+ const char *path;
+ int expected;
+ } test_cases[] = {
+ /* pattern "ign" from .gitignore */
+ { "file", 0 },
+ { "ign", 1 },
+ { "sub", 0 },
+ { "sub/file", 0 },
+ { "sub/ign", 1 },
+ { "sub/ign/file", 1 },
+ { "sub/ign/sub", 1 },
+ { "sub/ign/sub/file", 1 },
+ { "sub/sub", 0 },
+ { "sub/sub/file", 0 },
+ { "sub/sub/ign", 1 },
+ { "sub/sub/sub", 0 },
+ /* pattern "dir/" from .gitignore */
+ { "dir", 1 },
+ { "dir/", 1 },
+ { "sub/dir", 1 },
+ { "sub/dir/", 1 },
+ { "sub/dir/file", 1 }, /* contained in ignored parent */
+ { "sub/sub/dir", 0 }, /* dir is not actually a dir, but a file */
+ { NULL, 0 }
+ }, *one_test;
+
+ g_repo = cl_git_sandbox_init("attr");
+
+ for (one_test = test_cases; one_test->path != NULL; one_test++)
+ assert_ignored(one_test->expected, one_test->path);
+
+ /* confirm that ignore files were cached */
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
+}
+
+
+void test_ignore_status__1(void)
+{
+ g_repo = cl_git_sandbox_init("attr");
+
+ cl_git_rewritefile("attr/.gitignore", "/*.txt\n/dir/\n");
+ git_attr_cache_flush(g_repo);
+
+ assert_is_ignored("root_test4.txt");
+ refute_is_ignored("sub/subdir_test2.txt");
+ assert_is_ignored("dir");
+ assert_is_ignored("dir/");
+ refute_is_ignored("sub/dir");
+ refute_is_ignored("sub/dir/");
+}
+
+void test_ignore_status__empty_repo_with_gitignore_rewrite(void)
+{
+ status_entry_single st;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_mkfile(
+ "empty_standard_repo/look-ma.txt", "I'm going to be ignored!");
+
+ memset(&st, 0, sizeof(st));
+ cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
+ cl_assert(st.count == 1);
+ cl_assert(st.status == GIT_STATUS_WT_NEW);
+
+ cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
+ cl_assert(st.status == GIT_STATUS_WT_NEW);
+
+ refute_is_ignored("look-ma.txt");
+
+ cl_git_rewritefile("empty_standard_repo/.gitignore", "*.nomatch\n");
+
+ memset(&st, 0, sizeof(st));
+ cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
+ cl_assert(st.count == 2);
+ cl_assert(st.status == GIT_STATUS_WT_NEW);
+
+ cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
+ cl_assert(st.status == GIT_STATUS_WT_NEW);
+
+ refute_is_ignored("look-ma.txt");
+
+ cl_git_rewritefile("empty_standard_repo/.gitignore", "*.txt\n");
+
+ memset(&st, 0, sizeof(st));
+ cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
+ cl_assert(st.count == 2);
+ cl_assert(st.status == GIT_STATUS_IGNORED);
+
+ cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
+ cl_assert(st.status == GIT_STATUS_IGNORED);
+
+ assert_is_ignored("look-ma.txt");
+}
+
+void test_ignore_status__ignore_pattern_contains_space(void)
+{
+ unsigned int flags;
+ const mode_t mode = 0777;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_rewritefile("empty_standard_repo/.gitignore", "foo bar.txt\n");
+
+ cl_git_mkfile(
+ "empty_standard_repo/foo bar.txt", "I'm going to be ignored!");
+
+ cl_git_pass(git_status_file(&flags, g_repo, "foo bar.txt"));
+ cl_assert(flags == GIT_STATUS_IGNORED);
+
+ cl_git_pass(git_futils_mkdir_r("empty_standard_repo/foo", mode));
+ cl_git_mkfile("empty_standard_repo/foo/look-ma.txt", "I'm not going to be ignored!");
+
+ cl_git_pass(git_status_file(&flags, g_repo, "foo/look-ma.txt"));
+ cl_assert(flags == GIT_STATUS_WT_NEW);
+}
+
+void test_ignore_status__ignore_pattern_ignorecase(void)
+{
+ unsigned int flags;
+ bool ignore_case;
+ git_index *index;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_rewritefile("empty_standard_repo/.gitignore", "a.txt\n");
+
+ cl_git_mkfile("empty_standard_repo/A.txt", "Differs in case");
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ ignore_case = (git_index_caps(index) & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0;
+ git_index_free(index);
+
+ cl_git_pass(git_status_file(&flags, g_repo, "A.txt"));
+ cl_assert(flags == ignore_case ? GIT_STATUS_IGNORED : GIT_STATUS_WT_NEW);
+}
+
+void test_ignore_status__subdirectories(void)
+{
+ status_entry_single st;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_mkfile(
+ "empty_standard_repo/ignore_me", "I'm going to be ignored!");
+
+ cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n");
+
+ memset(&st, 0, sizeof(st));
+ cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
+ cl_assert_equal_i(2, st.count);
+ cl_assert(st.status == GIT_STATUS_IGNORED);
+
+ cl_git_pass(git_status_file(&st.status, g_repo, "ignore_me"));
+ cl_assert(st.status == GIT_STATUS_IGNORED);
+
+ assert_is_ignored("ignore_me");
+
+ /* I've changed libgit2 so that the behavior here now differs from
+ * core git but seems to make more sense. In core git, the following
+ * items are skipped completed, even if --ignored is passed to status.
+ * It you mirror these steps and run "git status -uall --ignored" then
+ * you will not see "test/ignore_me/" in the results.
+ *
+ * However, we had a couple reports of this as a bug, plus there is a
+ * similar circumstance where we were differing for core git when you
+ * used a rooted path for an ignore, so I changed this behavior.
+ */
+ cl_git_pass(git_futils_mkdir_r(
+ "empty_standard_repo/test/ignore_me", 0775));
+ cl_git_mkfile(
+ "empty_standard_repo/test/ignore_me/file", "I'm going to be ignored!");
+ cl_git_mkfile(
+ "empty_standard_repo/test/ignore_me/file2", "Me, too!");
+
+ memset(&st, 0, sizeof(st));
+ cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
+ cl_assert_equal_i(3, st.count);
+
+ cl_git_pass(git_status_file(&st.status, g_repo, "test/ignore_me/file"));
+ cl_assert(st.status == GIT_STATUS_IGNORED);
+
+ assert_is_ignored("test/ignore_me/file");
+}
+
+static void make_test_data(const char *reponame, const char **files)
+{
+ const char **scan;
+ size_t repolen = strlen(reponame) + 1;
+
+ g_repo = cl_git_sandbox_init(reponame);
+
+ for (scan = files; *scan != NULL; ++scan) {
+ cl_git_pass(git_futils_mkdir_relative(
+ *scan + repolen, reponame,
+ 0777, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST, NULL));
+ cl_git_mkfile(*scan, "contents");
+ }
+}
+
+static const char *test_repo_1 = "empty_standard_repo";
+static const char *test_files_1[] = {
+ "empty_standard_repo/dir/a/ignore_me",
+ "empty_standard_repo/dir/b/ignore_me",
+ "empty_standard_repo/dir/ignore_me",
+ "empty_standard_repo/ignore_also/file",
+ "empty_standard_repo/ignore_me",
+ "empty_standard_repo/test/ignore_me/file",
+ "empty_standard_repo/test/ignore_me/file2",
+ "empty_standard_repo/test/ignore_me/and_me/file",
+ NULL
+};
+
+void test_ignore_status__subdirectories_recursion(void)
+{
+ /* Let's try again with recursing into ignored dirs turned on */
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+ static const char *paths_r[] = {
+ ".gitignore",
+ "dir/a/ignore_me",
+ "dir/b/ignore_me",
+ "dir/ignore_me",
+ "ignore_also/file",
+ "ignore_me",
+ "test/ignore_me/and_me/file",
+ "test/ignore_me/file",
+ "test/ignore_me/file2",
+ };
+ static const unsigned int statuses_r[] = {
+ GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ };
+ static const char *paths_nr[] = {
+ ".gitignore",
+ "dir/a/ignore_me",
+ "dir/b/ignore_me",
+ "dir/ignore_me",
+ "ignore_also/",
+ "ignore_me",
+ "test/ignore_me/",
+ };
+ static const unsigned int statuses_nr[] = {
+ GIT_STATUS_WT_NEW,
+ GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ };
+
+ make_test_data(test_repo_1, test_files_1);
+ cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n/ignore_also\n");
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 9;
+ counts.expected_paths = paths_r;
+ counts.expected_statuses = statuses_r;
+
+ opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
+
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 7;
+ counts.expected_paths = paths_nr;
+ counts.expected_statuses = statuses_nr;
+
+ opts.flags = GIT_STATUS_OPT_DEFAULTS;
+
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+}
+
+void test_ignore_status__subdirectories_not_at_root(void)
+{
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+ static const char *paths_1[] = {
+ "dir/.gitignore",
+ "dir/a/ignore_me",
+ "dir/b/ignore_me",
+ "dir/ignore_me",
+ "ignore_also/file",
+ "ignore_me",
+ "test/.gitignore",
+ "test/ignore_me/and_me/file",
+ "test/ignore_me/file",
+ "test/ignore_me/file2",
+ };
+ static const unsigned int statuses_1[] = {
+ GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ GIT_STATUS_IGNORED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
+ GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
+ };
+
+ make_test_data(test_repo_1, test_files_1);
+ cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "ignore_me\n/ignore_also\n");
+ cl_git_rewritefile("empty_standard_repo/test/.gitignore", "and_me\n");
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 10;
+ counts.expected_paths = paths_1;
+ counts.expected_statuses = statuses_1;
+
+ opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
+
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+}
+
+void test_ignore_status__leading_slash_ignores(void)
+{
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+ static const char *paths_2[] = {
+ "dir/.gitignore",
+ "dir/a/ignore_me",
+ "dir/b/ignore_me",
+ "dir/ignore_me",
+ "ignore_also/file",
+ "ignore_me",
+ "test/.gitignore",
+ "test/ignore_me/and_me/file",
+ "test/ignore_me/file",
+ "test/ignore_me/file2",
+ };
+ static const unsigned int statuses_2[] = {
+ GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
+ GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
+ GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
+ };
+
+ make_test_data(test_repo_1, test_files_1);
+
+ cl_fake_home();
+ cl_git_mkfile("home/.gitignore", "/ignore_me\n");
+ {
+ git_config *cfg;
+ cl_git_pass(git_repository_config(&cfg, g_repo));
+ cl_git_pass(git_config_set_string(
+ cfg, "core.excludesfile", "~/.gitignore"));
+ git_config_free(cfg);
+ }
+
+ cl_git_rewritefile("empty_standard_repo/.git/info/exclude", "/ignore_also\n");
+ cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "/ignore_me\n");
+ cl_git_rewritefile("empty_standard_repo/test/.gitignore", "/and_me\n");
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 10;
+ counts.expected_paths = paths_2;
+ counts.expected_statuses = statuses_2;
+
+ opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
+
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+}
+
+void test_ignore_status__multiple_leading_slash(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/a.test",
+ "empty_standard_repo/b.test",
+ "empty_standard_repo/c.test",
+ "empty_standard_repo/d.test",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "a.test\n"
+ "/b.test\n"
+ "//c.test\n"
+ "///d.test\n");
+
+ assert_is_ignored("a.test");
+ assert_is_ignored("b.test");
+ refute_is_ignored("c.test");
+ refute_is_ignored("d.test");
+}
+
+void test_ignore_status__contained_dir_with_matching_name(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/subdir_match/aaa/subdir_match/file",
+ "empty_standard_repo/subdir_match/zzz_ignoreme",
+ NULL
+ };
+ static const char *expected_paths[] = {
+ "subdir_match/.gitignore",
+ "subdir_match/aaa/subdir_match/file",
+ "subdir_match/zzz_ignoreme",
+ };
+ static const unsigned int expected_statuses[] = {
+ GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED
+ };
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/subdir_match/.gitignore", "*_ignoreme\n");
+
+ refute_is_ignored("subdir_match/aaa/subdir_match/file");
+ assert_is_ignored("subdir_match/zzz_ignoreme");
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 3;
+ counts.expected_paths = expected_paths;
+ counts.expected_statuses = expected_statuses;
+
+ opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
+
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+}
+
+void test_ignore_status__trailing_slash_star(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/file",
+ "empty_standard_repo/subdir/file",
+ "empty_standard_repo/subdir/sub2/sub3/file",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/subdir/.gitignore", "/**/*\n");
+
+ refute_is_ignored("file");
+ assert_is_ignored("subdir/sub2/sub3/file");
+ assert_is_ignored("subdir/file");
+}
+
+void test_ignore_status__adding_internal_ignores(void)
+{
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ refute_is_ignored("one.txt");
+ refute_is_ignored("two.bar");
+
+ cl_git_pass(git_ignore_add_rule(g_repo, "*.nomatch\n"));
+
+ refute_is_ignored("one.txt");
+ refute_is_ignored("two.bar");
+
+ cl_git_pass(git_ignore_add_rule(g_repo, "*.txt\n"));
+
+ assert_is_ignored("one.txt");
+ refute_is_ignored("two.bar");
+
+ cl_git_pass(git_ignore_add_rule(g_repo, "*.bar\n"));
+
+ assert_is_ignored("one.txt");
+ assert_is_ignored("two.bar");
+
+ cl_git_pass(git_ignore_clear_internal_rules(g_repo));
+
+ refute_is_ignored("one.txt");
+ refute_is_ignored("two.bar");
+
+ cl_git_pass(git_ignore_add_rule(
+ g_repo, "multiple\n*.rules\n# comment line\n*.bar\n"));
+
+ refute_is_ignored("one.txt");
+ assert_is_ignored("two.bar");
+}
+
+void test_ignore_status__add_internal_as_first_thing(void)
+{
+ const char *add_me = "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/\ntmp/\n*.tmp\n\n";
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(git_ignore_add_rule(g_repo, add_me));
+
+ assert_is_ignored("one.tmp");
+ refute_is_ignored("two.bar");
+}
+
+void test_ignore_status__internal_ignores_inside_deep_paths(void)
+{
+ const char *add_me = "Debug\nthis/is/deep\npatterned*/dir\n";
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(git_ignore_add_rule(g_repo, add_me));
+
+ assert_is_ignored("Debug");
+ assert_is_ignored("and/Debug");
+ assert_is_ignored("really/Debug/this/file");
+ assert_is_ignored("Debug/what/I/say");
+
+ refute_is_ignored("and/NoDebug");
+ refute_is_ignored("NoDebug/this");
+ refute_is_ignored("please/NoDebug/this");
+
+ assert_is_ignored("this/is/deep");
+ /* pattern containing slash gets FNM_PATHNAME so all slashes must match */
+ refute_is_ignored("and/this/is/deep");
+ assert_is_ignored("this/is/deep/too");
+ /* pattern containing slash gets FNM_PATHNAME so all slashes must match */
+ refute_is_ignored("but/this/is/deep/and/ignored");
+
+ refute_is_ignored("this/is/not/deep");
+ refute_is_ignored("is/this/not/as/deep");
+ refute_is_ignored("this/is/deepish");
+ refute_is_ignored("xthis/is/deep");
+}
+
+void test_ignore_status__automatically_ignore_bad_files(void)
+{
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ assert_is_ignored(".git");
+ assert_is_ignored("this/file/.");
+ assert_is_ignored("path/../funky");
+ refute_is_ignored("path/whatever.c");
+
+ cl_git_pass(git_ignore_add_rule(g_repo, "*.c\n"));
+
+ assert_is_ignored(".git");
+ assert_is_ignored("this/file/.");
+ assert_is_ignored("path/../funky");
+ assert_is_ignored("path/whatever.c");
+
+ cl_git_pass(git_ignore_clear_internal_rules(g_repo));
+
+ assert_is_ignored(".git");
+ assert_is_ignored("this/file/.");
+ assert_is_ignored("path/../funky");
+ refute_is_ignored("path/whatever.c");
+}
+
+void test_ignore_status__filenames_with_special_prefixes_do_not_interfere_with_status_retrieval(void)
+{
+ status_entry_single st;
+ char *test_cases[] = {
+ "!file",
+ "#blah",
+ "[blah]",
+ "[attr]",
+ "[attr]blah",
+ NULL
+ };
+ int i;
+
+ for (i = 0; *(test_cases + i) != NULL; i++) {
+ git_buf file = GIT_BUF_INIT;
+ char *file_name = *(test_cases + i);
+ git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(git_buf_joinpath(&file, "empty_standard_repo", file_name));
+ cl_git_mkfile(git_buf_cstr(&file), "Please don't ignore me!");
+
+ memset(&st, 0, sizeof(st));
+ cl_git_pass(git_status_foreach(repo, cb_status__single, &st));
+ cl_assert(st.count == 1);
+ cl_assert(st.status == GIT_STATUS_WT_NEW);
+
+ cl_git_pass(git_status_file(&st.status, repo, file_name));
+ cl_assert(st.status == GIT_STATUS_WT_NEW);
+
+ cl_git_sandbox_cleanup();
+ git_buf_dispose(&file);
+ }
+}
+
+void test_ignore_status__issue_1766_negated_ignores(void)
+{
+ unsigned int status;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(git_futils_mkdir_r(
+ "empty_standard_repo/a", 0775));
+ cl_git_mkfile(
+ "empty_standard_repo/a/.gitignore", "*\n!.gitignore\n");
+ cl_git_mkfile(
+ "empty_standard_repo/a/ignoreme", "I should be ignored\n");
+
+ refute_is_ignored("a/.gitignore");
+ assert_is_ignored("a/ignoreme");
+
+ cl_git_pass(git_futils_mkdir_r(
+ "empty_standard_repo/b", 0775));
+ cl_git_mkfile(
+ "empty_standard_repo/b/.gitignore", "*\n!.gitignore\n");
+ cl_git_mkfile(
+ "empty_standard_repo/b/ignoreme", "I should be ignored\n");
+
+ refute_is_ignored("b/.gitignore");
+ assert_is_ignored("b/ignoreme");
+
+ /* shouldn't have changed results from first couple either */
+ refute_is_ignored("a/.gitignore");
+ assert_is_ignored("a/ignoreme");
+
+ /* status should find the two ignore files and nothing else */
+
+ cl_git_pass(git_status_file(&status, g_repo, "a/.gitignore"));
+ cl_assert_equal_i(GIT_STATUS_WT_NEW, (int)status);
+
+ cl_git_pass(git_status_file(&status, g_repo, "a/ignoreme"));
+ cl_assert_equal_i(GIT_STATUS_IGNORED, (int)status);
+
+ cl_git_pass(git_status_file(&status, g_repo, "b/.gitignore"));
+ cl_assert_equal_i(GIT_STATUS_WT_NEW, (int)status);
+
+ cl_git_pass(git_status_file(&status, g_repo, "b/ignoreme"));
+ cl_assert_equal_i(GIT_STATUS_IGNORED, (int)status);
+
+ {
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+ static const char *paths[] = {
+ "a/.gitignore",
+ "a/ignoreme",
+ "b/.gitignore",
+ "b/ignoreme",
+ };
+ static const unsigned int statuses[] = {
+ GIT_STATUS_WT_NEW,
+ GIT_STATUS_IGNORED,
+ GIT_STATUS_WT_NEW,
+ GIT_STATUS_IGNORED,
+ };
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 4;
+ counts.expected_paths = paths;
+ counts.expected_statuses = statuses;
+
+ opts.flags = GIT_STATUS_OPT_DEFAULTS;
+
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+ }
+}
+
+static void add_one_to_index(const char *file)
+{
+ git_index *index;
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_add_bypath(index, file));
+ git_index_free(index);
+}
+
+/* Some further broken scenarios that have been reported */
+void test_ignore_status__more_breakage(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/d1/pfx-d2/d3/d4/d5/tracked",
+ "empty_standard_repo/d1/pfx-d2/d3/d4/d5/untracked",
+ "empty_standard_repo/d1/pfx-d2/d3/d4/untracked",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "/d1/pfx-*\n"
+ "!/d1/pfx-d2/\n"
+ "/d1/pfx-d2/*\n"
+ "!/d1/pfx-d2/d3/\n"
+ "/d1/pfx-d2/d3/*\n"
+ "!/d1/pfx-d2/d3/d4/\n");
+ add_one_to_index("d1/pfx-d2/d3/d4/d5/tracked");
+
+ {
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+ static const char *files[] = {
+ ".gitignore",
+ "d1/pfx-d2/d3/d4/d5/tracked",
+ "d1/pfx-d2/d3/d4/d5/untracked",
+ "d1/pfx-d2/d3/d4/untracked",
+ };
+ static const unsigned int statuses[] = {
+ GIT_STATUS_WT_NEW,
+ GIT_STATUS_INDEX_NEW,
+ GIT_STATUS_WT_NEW,
+ GIT_STATUS_WT_NEW,
+ };
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 4;
+ counts.expected_paths = files;
+ counts.expected_statuses = statuses;
+ opts.flags = GIT_STATUS_OPT_DEFAULTS |
+ GIT_STATUS_OPT_INCLUDE_IGNORED |
+ GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+ }
+
+ refute_is_ignored("d1/pfx-d2/d3/d4/d5/tracked");
+ refute_is_ignored("d1/pfx-d2/d3/d4/d5/untracked");
+ refute_is_ignored("d1/pfx-d2/d3/d4/untracked");
+}
+
+void test_ignore_status__negative_ignores_inside_ignores(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/top/mid/btm/tracked",
+ "empty_standard_repo/top/mid/btm/untracked",
+ "empty_standard_repo/zoo/bar",
+ "empty_standard_repo/zoo/foo/bar",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "top\n"
+ "!top/mid/btm\n"
+ "zoo/*\n"
+ "!zoo/bar\n"
+ "!zoo/foo/bar\n");
+ add_one_to_index("top/mid/btm/tracked");
+
+ {
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ status_entry_counts counts;
+ static const char *files[] = {
+ ".gitignore", "top/mid/btm/tracked", "top/mid/btm/untracked",
+ "zoo/bar", "zoo/foo/bar",
+ };
+ static const unsigned int statuses[] = {
+ GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_NEW, GIT_STATUS_IGNORED,
+ GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED,
+ };
+
+ memset(&counts, 0x0, sizeof(status_entry_counts));
+ counts.expected_entry_count = 5;
+ counts.expected_paths = files;
+ counts.expected_statuses = statuses;
+ opts.flags = GIT_STATUS_OPT_DEFAULTS |
+ GIT_STATUS_OPT_INCLUDE_IGNORED |
+ GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
+ cl_git_pass(git_status_foreach_ext(
+ g_repo, &opts, cb_status__normal, &counts));
+
+ cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
+ cl_assert_equal_i(0, counts.wrong_status_flags_count);
+ cl_assert_equal_i(0, counts.wrong_sorted_path);
+ }
+
+ assert_is_ignored("top/mid/btm/tracked");
+ assert_is_ignored("top/mid/btm/untracked");
+ refute_is_ignored("foo/bar");
+}
+
+void test_ignore_status__negative_ignores_in_slash_star(void)
+{
+ git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
+ git_status_list *list;
+ int found_look_ma = 0, found_what_about = 0;
+ size_t i;
+ static const char *test_files[] = {
+ "empty_standard_repo/bin/look-ma.txt",
+ "empty_standard_repo/bin/what-about-me.txt",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "bin/*\n"
+ "!bin/w*\n");
+
+ assert_is_ignored("bin/look-ma.txt");
+ refute_is_ignored("bin/what-about-me.txt");
+
+ status_opts.flags = GIT_STATUS_OPT_DEFAULTS;
+ cl_git_pass(git_status_list_new(&list, g_repo, &status_opts));
+ for (i = 0; i < git_status_list_entrycount(list); i++) {
+ const git_status_entry *entry = git_status_byindex(list, i);
+
+ if (!strcmp("bin/look-ma.txt", entry->index_to_workdir->new_file.path))
+ found_look_ma = 1;
+
+ if (!strcmp("bin/what-about-me.txt", entry->index_to_workdir->new_file.path))
+ found_what_about = 1;
+ }
+ git_status_list_free(list);
+
+ cl_assert(found_look_ma);
+ cl_assert(found_what_about);
+}
+
+void test_ignore_status__negative_ignores_without_trailing_slash_inside_ignores(void)
+{
+ git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
+ git_status_list *list;
+ int found_parent_file = 0, found_parent_child1_file = 0, found_parent_child2_file = 0;
+ size_t i;
+ static const char *test_files[] = {
+ "empty_standard_repo/parent/file.txt",
+ "empty_standard_repo/parent/force.txt",
+ "empty_standard_repo/parent/child1/file.txt",
+ "empty_standard_repo/parent/child2/file.txt",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "parent/*\n"
+ "!parent/force.txt\n"
+ "!parent/child1\n"
+ "!parent/child2/\n");
+
+ add_one_to_index("parent/force.txt");
+
+ assert_is_ignored("parent/file.txt");
+ refute_is_ignored("parent/force.txt");
+ refute_is_ignored("parent/child1/file.txt");
+ refute_is_ignored("parent/child2/file.txt");
+
+ status_opts.flags = GIT_STATUS_OPT_DEFAULTS;
+ cl_git_pass(git_status_list_new(&list, g_repo, &status_opts));
+ for (i = 0; i < git_status_list_entrycount(list); i++) {
+ const git_status_entry *entry = git_status_byindex(list, i);
+
+ if (!entry->index_to_workdir)
+ continue;
+
+ if (!strcmp("parent/file.txt", entry->index_to_workdir->new_file.path))
+ found_parent_file = 1;
+
+ if (!strcmp("parent/force.txt", entry->index_to_workdir->new_file.path))
+ found_parent_file = 1;
+
+ if (!strcmp("parent/child1/file.txt", entry->index_to_workdir->new_file.path))
+ found_parent_child1_file = 1;
+
+ if (!strcmp("parent/child2/file.txt", entry->index_to_workdir->new_file.path))
+ found_parent_child2_file = 1;
+ }
+ git_status_list_free(list);
+
+ cl_assert(found_parent_file);
+ cl_assert(found_parent_child1_file);
+ cl_assert(found_parent_child2_file);
+}
+
+void test_ignore_status__negative_directory_ignores(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/parent/child1/bar.txt",
+ "empty_standard_repo/parent/child2/bar.txt",
+ "empty_standard_repo/parent/child3/foo.txt",
+ "empty_standard_repo/parent/child4/bar.txt",
+ "empty_standard_repo/parent/nested/child5/bar.txt",
+ "empty_standard_repo/parent/nested/child6/bar.txt",
+ "empty_standard_repo/parent/nested/child7/bar.txt",
+ "empty_standard_repo/padded_parent/child8/bar.txt",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "foo.txt\n"
+ "parent/child1\n"
+ "parent/child2\n"
+ "parent/child4\n"
+ "parent/nested/child5\n"
+ "nested/child6\n"
+ "nested/child7\n"
+ "padded_parent/child8\n"
+ /* test simple exact match */
+ "!parent/child1\n"
+ /* test negating file without negating dir */
+ "!parent/child2/bar.txt\n"
+ /* test negative pattern on dir with its content
+ * being ignored */
+ "!parent/child3\n"
+ /* test with partial match at end */
+ "!child4\n"
+ /* test with partial match with '/' at end */
+ "!nested/child5\n"
+ /* test with complete match */
+ "!nested/child6\n"
+ /* test with trailing '/' */
+ "!child7/\n"
+ /* test with partial dir match */
+ "!_parent/child8\n");
+
+ refute_is_ignored("parent/child1/bar.txt");
+ assert_is_ignored("parent/child2/bar.txt");
+ assert_is_ignored("parent/child3/foo.txt");
+ refute_is_ignored("parent/child4/bar.txt");
+ assert_is_ignored("parent/nested/child5/bar.txt");
+ refute_is_ignored("parent/nested/child6/bar.txt");
+ refute_is_ignored("parent/nested/child7/bar.txt");
+ assert_is_ignored("padded_parent/child8/bar.txt");
+}
+
+void test_ignore_status__unignore_entry_in_ignored_dir(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/bar.txt",
+ "empty_standard_repo/parent/bar.txt",
+ "empty_standard_repo/parent/child/bar.txt",
+ "empty_standard_repo/nested/parent/child/bar.txt",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "bar.txt\n"
+ "!parent/child/bar.txt\n");
+
+ assert_is_ignored("bar.txt");
+ assert_is_ignored("parent/bar.txt");
+ refute_is_ignored("parent/child/bar.txt");
+ assert_is_ignored("nested/parent/child/bar.txt");
+}
+
+void test_ignore_status__do_not_unignore_basename_prefix(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/foo_bar.txt",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "foo_bar.txt\n"
+ "!bar.txt\n");
+
+ assert_is_ignored("foo_bar.txt");
+}
+
+void test_ignore_status__filename_with_cr(void)
+{
+ int ignored;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+ cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\r\n");
+
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
+ cl_assert_equal_i(1, ignored);
+
+ cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\n");
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
+ cl_assert_equal_i(1, ignored);
+
+ cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\n");
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
+ cl_assert_equal_i(1, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
+ cl_assert_equal_i(0, ignored);
+
+ cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\r\n");
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
+ cl_assert_equal_i(1, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
+ cl_assert_equal_i(0, ignored);
+
+ cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\n");
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
+ cl_assert_equal_i(0, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon"));
+ cl_assert_equal_i(1, ignored);
+}
+
+void test_ignore_status__subdir_doesnt_match_above(void)
+{
+ int ignored, icase = 0, error;
+ git_config *cfg;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(git_repository_config_snapshot(&cfg, g_repo));
+ error = git_config_get_bool(&icase, cfg, "core.ignorecase");
+ git_config_free(cfg);
+ if (error == GIT_ENOTFOUND)
+ error = 0;
+
+ cl_git_pass(error);
+
+ cl_git_pass(p_mkdir("empty_standard_repo/src", 0777));
+ cl_git_pass(p_mkdir("empty_standard_repo/src/src", 0777));
+ cl_git_mkfile("empty_standard_repo/src/.gitignore", "src\n");
+ cl_git_mkfile("empty_standard_repo/.gitignore", "");
+
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/test.txt"));
+ cl_assert_equal_i(0, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/src/test.txt"));
+ cl_assert_equal_i(1, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/foo/test.txt"));
+ cl_assert_equal_i(0, ignored);
+
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "SRC/src/test.txt"));
+ cl_assert_equal_i(icase, ignored);
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/SRC/test.txt"));
+ cl_assert_equal_i(icase, ignored);
+}
+
+void test_ignore_status__negate_exact_previous(void)
+{
+ int ignored;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_mkfile("empty_standard_repo/.gitignore", "*.com\ntags\n!tags/\n.buildpath");
+ cl_git_mkfile("empty_standard_repo/.buildpath", "");
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, ".buildpath"));
+ cl_assert_equal_i(1, ignored);
+}
+
+void test_ignore_status__negate_starstar(void)
+{
+ int ignored;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_mkfile("empty_standard_repo/.gitignore",
+ "code/projects/**/packages/*\n"
+ "!code/projects/**/packages/repositories.config");
+
+ cl_git_pass(git_futils_mkdir_r("empty_standard_repo/code/projects/foo/bar/packages", 0777));
+ cl_git_mkfile("empty_standard_repo/code/projects/foo/bar/packages/repositories.config", "");
+
+ cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config"));
+ cl_assert_equal_i(0, ignored);
+}
+
+void test_ignore_status__ignore_all_toplevel_dirs_include_files(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/README.md",
+ "empty_standard_repo/src/main.c",
+ "empty_standard_repo/src/foo/foo.c",
+ "empty_standard_repo/dist/foo.o",
+ "empty_standard_repo/dist/main.o",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "/*/\n"
+ "!/src\n");
+
+ assert_is_ignored("dist/foo.o");
+ assert_is_ignored("dist/main.o");
+
+ refute_is_ignored("README.md");
+ refute_is_ignored("src/foo.c");
+ refute_is_ignored("src/foo/foo.c");
+}
+
+void test_ignore_status__subdir_ignore_all_toplevel_dirs_include_files(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/project/README.md",
+ "empty_standard_repo/project/src/main.c",
+ "empty_standard_repo/project/src/foo/foo.c",
+ "empty_standard_repo/project/dist/foo.o",
+ "empty_standard_repo/project/dist/main.o",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/project/.gitignore",
+ "/*/\n"
+ "!/src\n");
+
+ assert_is_ignored("project/dist/foo.o");
+ assert_is_ignored("project/dist/main.o");
+
+ refute_is_ignored("project/src/foo.c");
+ refute_is_ignored("project/src/foo/foo.c");
+ refute_is_ignored("project/README.md");
+}
+
+void test_ignore_status__subdir_ignore_everything_except_certain_files(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/project/README.md",
+ "empty_standard_repo/project/some_file",
+ "empty_standard_repo/project/src/main.c",
+ "empty_standard_repo/project/src/foo/foo.c",
+ "empty_standard_repo/project/dist/foo.o",
+ "empty_standard_repo/project/dist/main.o",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/project/.gitignore",
+ "/*\n"
+ "!/src\n"
+ "!README.md\n");
+
+ assert_is_ignored("project/some_file");
+ assert_is_ignored("project/dist/foo.o");
+ assert_is_ignored("project/dist/main.o");
+
+ refute_is_ignored("project/README.md");
+ refute_is_ignored("project/src/foo.c");
+ refute_is_ignored("project/src/foo/foo.c");
+}
+
+void test_ignore_status__deeper(void)
+{
+ const char *test_files[] = {
+ "empty_standard_repo/foo.data",
+ "empty_standard_repo/bar.data",
+ "empty_standard_repo/dont_ignore/foo.data",
+ "empty_standard_repo/dont_ignore/bar.data",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile("empty_standard_repo/.gitignore",
+ "*.data\n"
+ "!dont_ignore/*.data\n");
+
+ assert_is_ignored("foo.data");
+ assert_is_ignored("bar.data");
+
+ refute_is_ignored("dont_ignore/foo.data");
+ refute_is_ignored("dont_ignore/bar.data");
+}
+
+void test_ignore_status__unignored_dir_with_ignored_contents(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/dir/a.test",
+ "empty_standard_repo/dir/subdir/a.test",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "*.test\n"
+ "!dir/*\n");
+
+ refute_is_ignored("dir/a.test");
+ assert_is_ignored("dir/subdir/a.test");
+}
+
+void test_ignore_status__unignored_subdirs(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/dir/a.test",
+ "empty_standard_repo/dir/subdir/a.test",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "dir/*\n"
+ "!dir/*/\n");
+
+ assert_is_ignored("dir/a.test");
+ refute_is_ignored("dir/subdir/a.test");
+}
+
+void test_ignore_status__skips_bom(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/a.test",
+ "empty_standard_repo/b.test",
+ "empty_standard_repo/c.test",
+ "empty_standard_repo/foo.txt",
+ "empty_standard_repo/bar.txt",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ "\xEF\xBB\xBF*.test\n");
+
+ assert_is_ignored("a.test");
+ assert_is_ignored("b.test");
+ assert_is_ignored("c.test");
+ refute_is_ignored("foo.txt");
+ refute_is_ignored("bar.txt");
+}
+
+void test_ignore_status__leading_spaces_are_significant(void)
+{
+ static const char *test_files[] = {
+ "empty_standard_repo/a.test",
+ "empty_standard_repo/b.test",
+ "empty_standard_repo/c.test",
+ "empty_standard_repo/d.test",
+ NULL
+ };
+
+ make_test_data("empty_standard_repo", test_files);
+ cl_git_mkfile(
+ "empty_standard_repo/.gitignore",
+ " a.test\n"
+ "# this is a comment\n"
+ "b.test\n"
+ "\tc.test\n"
+ " # not a comment\n"
+ "d.test\n");
+
+ refute_is_ignored("a.test");
+ assert_is_ignored(" a.test");
+ refute_is_ignored("# this is a comment");
+ assert_is_ignored("b.test");
+ refute_is_ignored("c.test");
+ assert_is_ignored("\tc.test");
+ assert_is_ignored(" # not a comment");
+ assert_is_ignored("d.test");
+}
+
+void test_ignore_status__override_nested_wildcard_unignore(void)
+{
+ git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
+ git_status_list *statuslist;
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ const git_status_entry *status;
+
+ cl_git_pass(git_futils_mkdir_r("empty_standard_repo/dir", 0777));
+ cl_git_pass(git_futils_mkdir_r("empty_standard_repo/dir/subdir", 0777));
+ cl_git_mkfile("empty_standard_repo/.gitignore", "a.test\n");
+ cl_git_mkfile("empty_standard_repo/dir/.gitignore", "!*.test\n");
+ cl_git_mkfile("empty_standard_repo/dir/subdir/.gitignore", "a.test\n");
+ cl_git_mkfile("empty_standard_repo/dir/a.test", "pong");
+ cl_git_mkfile("empty_standard_repo/dir/subdir/a.test", "pong");
+
+ opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
+ opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
+
+ cl_git_pass(git_status_list_new(&statuslist, repo, &opts));
+ cl_assert_equal_sz(4, git_status_list_entrycount(statuslist));
+
+ status = git_status_byindex(statuslist, 0);
+ cl_assert(status != NULL);
+ cl_assert_equal_s(".gitignore", status->index_to_workdir->old_file.path);
+ cl_assert_equal_i(GIT_STATUS_WT_NEW, status->status);
+
+ status = git_status_byindex(statuslist, 1);
+ cl_assert(status != NULL);
+ cl_assert_equal_s("dir/.gitignore", status->index_to_workdir->old_file.path);
+ cl_assert_equal_i(GIT_STATUS_WT_NEW, status->status);
+
+ status = git_status_byindex(statuslist, 2);
+ cl_assert(status != NULL);
+ cl_assert_equal_s("dir/a.test", status->index_to_workdir->old_file.path);
+ cl_assert_equal_i(GIT_STATUS_WT_NEW, status->status);
+
+ status = git_status_byindex(statuslist, 3);
+ cl_assert(status != NULL);
+ cl_assert_equal_s("dir/subdir/.gitignore", status->index_to_workdir->old_file.path);
+ cl_assert_equal_i(GIT_STATUS_WT_NEW, status->status);
+
+ git_status_list_free(statuslist);
+}
#include "clar_libgit2.h"
#include "../status/status_helpers.h"
#include "posix.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo = NULL;
#define TEST_DIR "addall"
git_repository *repo,
size_t index_adds, size_t index_dels, size_t index_mods,
size_t wt_adds, size_t wt_dels, size_t wt_mods, size_t ignores,
- size_t conflicts, const char *file, int line)
+ size_t conflicts, const char *file, const char *func, int line)
{
index_status_counts vals;
cl_git_pass(git_status_foreach(repo, index_status_cb, &vals));
clar__assert_equal(
- file,line,"wrong index adds", 1, "%"PRIuZ, index_adds, vals.index_adds);
+ file,func,line,"wrong index adds", 1, "%"PRIuZ, index_adds, vals.index_adds);
clar__assert_equal(
- file,line,"wrong index dels", 1, "%"PRIuZ, index_dels, vals.index_dels);
+ file,func,line,"wrong index dels", 1, "%"PRIuZ, index_dels, vals.index_dels);
clar__assert_equal(
- file,line,"wrong index mods", 1, "%"PRIuZ, index_mods, vals.index_mods);
+ file,func,line,"wrong index mods", 1, "%"PRIuZ, index_mods, vals.index_mods);
clar__assert_equal(
- file,line,"wrong workdir adds", 1, "%"PRIuZ, wt_adds, vals.wt_adds);
+ file,func,line,"wrong workdir adds", 1, "%"PRIuZ, wt_adds, vals.wt_adds);
clar__assert_equal(
- file,line,"wrong workdir dels", 1, "%"PRIuZ, wt_dels, vals.wt_dels);
+ file,func,line,"wrong workdir dels", 1, "%"PRIuZ, wt_dels, vals.wt_dels);
clar__assert_equal(
- file,line,"wrong workdir mods", 1, "%"PRIuZ, wt_mods, vals.wt_mods);
+ file,func,line,"wrong workdir mods", 1, "%"PRIuZ, wt_mods, vals.wt_mods);
clar__assert_equal(
- file,line,"wrong ignores", 1, "%"PRIuZ, ignores, vals.ignores);
+ file,func,line,"wrong ignores", 1, "%"PRIuZ, ignores, vals.ignores);
clar__assert_equal(
- file,line,"wrong conflicts", 1, "%"PRIuZ, conflicts, vals.conflicts);
+ file,func,line,"wrong conflicts", 1, "%"PRIuZ, conflicts, vals.conflicts);
}
#define check_status(R,IA,ID,IM,WA,WD,WM,IG,C) \
- check_status_at_line(R,IA,ID,IM,WA,WD,WM,IG,C,__FILE__,__LINE__)
+ check_status_at_line(R,IA,ID,IM,WA,WD,WM,IG,C,__FILE__,__func__,__LINE__)
static void check_stat_data(git_index *index, const char *path, bool match)
{
git_index_entry new_entry;
int symlinks;
- cl_git_pass(git_repository__cvar(&symlinks, g_repo, GIT_CVAR_SYMLINKS));
+ cl_git_pass(git_repository__configmap_lookup(&symlinks, g_repo, GIT_CONFIGMAP_SYMLINKS));
if (symlinks)
cl_skip();
git_buf details = GIT_BUF_INIT;
git_buf_printf(&details, "filename=%s, system=%s, autocrlf=%s, safecrlf=%s, attrs={%s}",
basename, cd->systype, cd->autocrlf, cd->safecrlf, cd->attrs);
- clar__fail(__FILE__, __LINE__,
+ clar__fail(__FILE__, __func__, __LINE__,
"index contents did not match expected", details.ptr, 0);
git_buf_dispose(&details);
}
git_buf_dispose(&content);
}
-#define add_and_check_mode(I,F,X) add_and_check_mode_(I,F,X,__FILE__,__LINE__)
+#define add_and_check_mode(I,F,X) add_and_check_mode_(I,F,X,__FILE__,__func__,__LINE__)
static void add_and_check_mode_(
git_index *index, const char *filename, unsigned int expect_mode,
- const char *file, int line)
+ const char *file, const char *func, int line)
{
size_t pos;
const git_index_entry *entry;
cl_git_pass(git_index_add_bypath(index, filename));
clar__assert(!git_index_find(&pos, index, filename),
- file, line, "Cannot find index entry", NULL, 1);
+ file, func, line, "Cannot find index entry", NULL, 1);
entry = git_index_get_byindex(index, pos);
- clar__assert_equal(file, line, "Expected mode does not match index",
+ clar__assert_equal(file, func, line, "Expected mode does not match index",
1, "%07o", (unsigned int)entry->mode, (unsigned int)expect_mode);
}
git_index_free(index);
}
-#define add_entry_and_check_mode(I,FF,X) add_entry_and_check_mode_(I,FF,X,__FILE__,__LINE__)
+#define add_entry_and_check_mode(I,FF,X) add_entry_and_check_mode_(I,FF,X,__FILE__,__func__,__LINE__)
static void add_entry_and_check_mode_(
git_index *index, bool from_file, git_filemode_t mode,
- const char *file, int line)
+ const char *file, const char *func, int line)
{
size_t pos;
const git_index_entry* entry;
git_index_entry new_entry;
/* If old_filename exists, we copy that to the new file, and test
- * git_index_add(), otherwise create a new entry testing git_index_add_frombuffer
+ * git_index_add(), otherwise create a new entry testing git_index_add_from_buffer
*/
if (from_file)
{
clar__assert(!git_index_find(&pos, index, "exec_off"),
- file, line, "Cannot find original index entry", NULL, 1);
+ file, func, line, "Cannot find original index entry", NULL, 1);
entry = git_index_get_byindex(index, pos);
if (from_file)
{
clar__assert(!git_index_add(index, &new_entry),
- file, line, "Cannot add index entry", NULL, 1);
+ file, func, line, "Cannot add index entry", NULL, 1);
}
else
{
const char *content = "hey there\n";
- clar__assert(!git_index_add_frombuffer(index, &new_entry, content, strlen(content)),
- file, line, "Cannot add index entry from buffer", NULL, 1);
+ clar__assert(!git_index_add_from_buffer(index, &new_entry, content, strlen(content)),
+ file, func, line, "Cannot add index entry from buffer", NULL, 1);
}
clar__assert(!git_index_find(&pos, index, "filemodes/explicit_test"),
- file, line, "Cannot find new index entry", NULL, 1);
+ file, func, line, "Cannot find new index entry", NULL, 1);
entry = git_index_get_byindex(index, pos);
- clar__assert_equal(file, line, "Expected mode does not match index",
+ clar__assert_equal(file, func, line, "Expected mode does not match index",
1, "%07o", (unsigned int)entry->mode, (unsigned int)mode);
}
git_index *index;
/* These tests should run and work everywhere, as the filemode is
- * given explicitly to git_index_add or git_index_add_frombuffer
+ * given explicitly to git_index_add or git_index_add_from_buffer
*/
cl_repo_set_bool(g_repo, "core.filemode", false);
new_entry.path = "dummy-file.txt";
new_entry.mode = GIT_FILEMODE_BLOB;
- cl_git_pass(git_index_add_frombuffer(index,
+ cl_git_pass(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
new_entry.path = "dummy-file.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
- cl_git_pass(git_index_add_frombuffer(index,
+ cl_git_pass(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert((ret_entry = git_index_get_bypath(index, "dummy-file.txt", 0)));
new_entry.path = "dummy-link.txt";
new_entry.mode = GIT_FILEMODE_LINK;
- cl_git_pass(git_index_add_frombuffer(index,
+ cl_git_pass(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert((ret_entry = git_index_get_bypath(index, "dummy-link.txt", 0)));
new_entry.path = "invalid_mode.txt";
new_entry.mode = GIT_FILEMODE_TREE;
- cl_git_fail(git_index_add_frombuffer(index,
+ cl_git_fail(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
new_entry.path = "invalid_mode.txt";
new_entry.mode = GIT_FILEMODE_COMMIT;
- cl_git_fail(git_index_add_frombuffer(index,
+ cl_git_fail(git_index_add_from_buffer(index,
&new_entry, content, strlen(content)));
cl_assert_equal_p(NULL, git_index_get_bypath(index, "invalid_mode.txt", 0));
expect = try_create_file_with_nsec_timestamp(nsec_path.ptr);
- p_unlink(nsec_path.ptr);
+ cl_must_pass(p_unlink(nsec_path.ptr));
git_buf_dispose(&nsec_path);
/* Put 'C' into the index */
new_entry.path = "C";
new_entry.mode = GIT_FILEMODE_BLOB;
- cl_git_pass(git_index_add_frombuffer(index, &new_entry, "hello!\n", 7));
+ cl_git_pass(git_index_add_from_buffer(index, &new_entry, "hello!\n", 7));
git_index_free(index);
git_buf_dispose(&path);
struct test_entry {
size_t index;
char path[128];
- git_off_t file_size;
+ off64_t file_size;
git_time_t mtime;
};
memset(&entry, 0x0, sizeof(git_index_entry));
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "test.txt";
- cl_git_pass(git_index_add_frombuffer(index, &entry,
+ cl_git_pass(git_index_add_from_buffer(index, &entry,
content, strlen(content)));
/* Wow... it worked! */
/* Index is dirty after adding an entry */
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "test.txt";
- cl_git_pass(git_index_add_frombuffer(index, &entry, "Hi.\n", 4));
+ cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
cl_assert(git_index_entrycount(index) == 1);
cl_assert(git_index_is_dirty(index));
cl_assert(!git_index_is_dirty(index));
/* Index is dirty when we do an unforced read with dirty content */
- cl_git_pass(git_index_add_frombuffer(index, &entry, "Hi.\n", 4));
+ cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
cl_assert(git_index_entrycount(index) == 1);
cl_assert(git_index_is_dirty(index));
/* Index is dirty after adding an entry */
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "test.txt";
- cl_git_pass(git_index_add_frombuffer(index, &entry, "Hi.\n", 4));
+ cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
cl_assert(git_index_is_dirty(index));
cl_git_pass(git_checkout_head(repo, NULL));
/* Index is dirty (again) after adding an entry */
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "test.txt";
- cl_git_pass(git_index_add_frombuffer(index, &entry, "Hi.\n", 4));
+ cl_git_pass(git_index_add_from_buffer(index, &entry, "Hi.\n", 4));
cl_assert(git_index_is_dirty(index));
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, 1));
memset(&entry, 0x0, sizeof(git_index_entry));
entry.mode = GIT_FILEMODE_BLOB;
entry.path = "test.txt";
- cl_git_pass(git_index_add_frombuffer(index, &entry,
+ cl_git_pass(git_index_add_from_buffer(index, &entry,
content, strlen(content)));
/* Wow... it worked! */
{
git_repository *repo;
- p_mkdir("invalid", 0700);
-
+ cl_must_pass(p_mkdir("invalid", 0700));
cl_git_pass(git_repository_init(&repo, "./invalid", 0));
cl_must_pass(p_mkdir("./invalid/subdir", 0777));
"xz",
"xyzzyx"
};
+ git_repository *repo;
git_index_entry entry;
git_index *index;
size_t i;
memset(&entry, 0, sizeof(entry));
entry.path = paths[i];
entry.mode = GIT_FILEMODE_BLOB;
- cl_git_pass(git_index_add_frombuffer(index, &entry, paths[i],
+ cl_git_pass(git_index_add_from_buffer(index, &entry, paths[i],
strlen(paths[i]) + 1));
}
cl_assert_equal_sz(git_index_entrycount(index), ARRAY_SIZE(paths));
cl_git_pass(git_index_write(index));
git_index_free(index);
- cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_repository_open(&repo, git_repository_path(g_repo)));
+ cl_git_pass(git_repository_index(&index, repo));
cl_assert(git_index_version(index) == 4);
for (i = 0; i < ARRAY_SIZE(paths); i++) {
}
git_index_free(index);
+ git_repository_free(repo);
}
void test_index_version__v4_uses_path_compression(void)
path[ARRAY_SIZE(path) - 3] = i;
path[ARRAY_SIZE(path) - 2] = j;
path[ARRAY_SIZE(path) - 1] = '\0';
- cl_git_pass(git_index_add_frombuffer(index, &entry, buf, sizeof(buf)));
+ cl_git_pass(git_index_add_from_buffer(index, &entry, buf, sizeof(buf)));
}
}
#include "clar_libgit2.h"
#include "iterator.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "iterator_helpers.h"
#include "../submodule/submodule_helpers.h"
#include <stdarg.h>
#include "clar_libgit2.h"
#include "iterator.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "iterator_helpers.h"
#include <stdarg.h>
#include "clar_libgit2.h"
#include "iterator.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "tree.h"
#include "../submodule/submodule_helpers.h"
#include "../diff/diff_helpers.h"
#include "clar_libgit2.h"
#include "iterator.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "../submodule/submodule_helpers.h"
#include "../merge/merge_helpers.h"
#include "iterator_helpers.h"
void test_iterator_workdir__0(void)
{
- workdir_iterator_test("attr", NULL, NULL, 23, 5, NULL, "ign");
+ workdir_iterator_test("attr", NULL, NULL, 24, 5, NULL, "ign");
}
static const char *status_paths[] = {
"heads/subtrees",
"heads/test",
"heads/testrepo-worktree",
+ "symref",
"tags/e90810b",
"tags/foo/bar",
"tags/foo/foo/bar",
cl_git_pass(git_iterator_for_filesystem(
&i, "testrepo/.git/refs", NULL));
- expect_iterator_items(i, 16, expect_base, 16, expect_base);
+ expect_iterator_items(i, 17, expect_base, 17, expect_base);
git_iterator_free(i);
}
-/* Lots of empty dirs, or nearly empty ones, make the old workdir
- * iterator cry. Also, segfault.
+/*
+ * Lots of empty dirs, or nearly empty ones, make the old workdir
+ * iterator cry. Also, segfault.
*/
void test_iterator_workdir__filesystem_gunk(void)
{
- git_iterator *i;
git_buf parent = GIT_BUF_INIT;
+ git_iterator *i;
int n;
if (!cl_is_env_set("GITTEST_INVASIVE_SPEED"))
for (n = 0; n < 100000; n++) {
git_buf_clear(&parent);
- git_buf_printf(&parent, "%s/refs/heads/foo/%d/subdir",
- git_repository_path(g_repo), n);
- cl_assert(!git_buf_oom(&parent));
-
+ cl_git_pass(git_buf_printf(&parent, "%s/refs/heads/foo/%d/subdir", git_repository_path(g_repo), n));
cl_git_pass(git_futils_mkdir(parent.ptr, 0775, GIT_MKDIR_PATH));
}
cl_git_pass(git_iterator_for_filesystem(&i, "testrepo/.git/refs", NULL));
- /* should only have 16 items, since we're not asking for trees to be
+ /*
+ * Should only have 17 items, since we're not asking for trees to be
* returned. the goal of this test is simply to not crash.
*/
- expect_iterator_items(i, 16, NULL, 15, NULL);
+ expect_iterator_items(i, 17, NULL, 16, NULL);
+
git_iterator_free(i);
git_buf_dispose(&parent);
}
--- /dev/null
+/*
+NOTE: this is the implementation for both merge/trees/analysis.c and merge/workdir/analysis.c
+You probably want to make changes to both files.
+*/
+
+#include "clar_libgit2.h"
+#include "git2/repository.h"
+#include "git2/merge.h"
+#include "git2/annotated_commit.h"
+#include "git2/sys/index.h"
+#include "merge.h"
+#include "merge_helpers.h"
+#include "refs.h"
+#include "posix.h"
+
+#define TEST_REPO_PATH "merge-resolve"
+
+#define UPTODATE_BRANCH "master"
+#define PREVIOUS_BRANCH "previous"
+
+#define FASTFORWARD_BRANCH "ff_branch"
+#define FASTFORWARD_ID "fd89f8cffb663ac89095a0f9764902e93ceaca6a"
+
+#define NOFASTFORWARD_BRANCH "branch"
+#define NOFASTFORWARD_ID "7cb63eed597130ba4abb87b3e544b85021905520"
+
+static git_repository *sandbox;
+static git_repository *repo;
+
+void test_merge_analysis__initialize_with_bare_repository(void)
+{
+ sandbox = cl_git_sandbox_init(TEST_REPO_PATH);
+ cl_git_pass(git_repository_open_ext(&repo, git_repository_path(sandbox),
+ GIT_REPOSITORY_OPEN_BARE, NULL));
+}
+
+void test_merge_analysis__initialize_with_nonbare_repository(void)
+{
+ sandbox = cl_git_sandbox_init(TEST_REPO_PATH);
+ cl_git_pass(git_repository_open_ext(&repo, git_repository_workdir(sandbox),
+ 0, NULL));
+}
+
+void test_merge_analysis__cleanup(void)
+{
+ git_repository_free(repo);
+ cl_git_sandbox_cleanup();
+}
+
+static void analysis_from_branch(
+ git_merge_analysis_t *merge_analysis,
+ git_merge_preference_t *merge_pref,
+ const char *our_branchname,
+ const char *their_branchname)
+{
+ git_buf our_refname = GIT_BUF_INIT;
+ git_buf their_refname = GIT_BUF_INIT;
+ git_reference *our_ref;
+ git_reference *their_ref;
+ git_annotated_commit *their_head;
+
+ if (our_branchname != NULL) {
+ cl_git_pass(git_buf_printf(&our_refname, "%s%s", GIT_REFS_HEADS_DIR, our_branchname));
+ cl_git_pass(git_reference_lookup(&our_ref, repo, git_buf_cstr(&our_refname)));
+ } else {
+ cl_git_pass(git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE));
+ }
+
+ cl_git_pass(git_buf_printf(&their_refname, "%s%s", GIT_REFS_HEADS_DIR, their_branchname));
+
+ cl_git_pass(git_reference_lookup(&their_ref, repo, git_buf_cstr(&their_refname)));
+ cl_git_pass(git_annotated_commit_from_ref(&their_head, repo, their_ref));
+
+ cl_git_pass(git_merge_analysis_for_ref(merge_analysis, merge_pref, repo, our_ref, (const git_annotated_commit **)&their_head, 1));
+
+ git_buf_dispose(&our_refname);
+ git_buf_dispose(&their_refname);
+ git_annotated_commit_free(their_head);
+ git_reference_free(our_ref);
+ git_reference_free(their_ref);
+}
+
+void test_merge_analysis__fastforward(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, FASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL|GIT_MERGE_ANALYSIS_FASTFORWARD, merge_analysis);
+}
+
+void test_merge_analysis__no_fastforward(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, NOFASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis);
+}
+
+void test_merge_analysis__uptodate(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, UPTODATE_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis);
+}
+
+void test_merge_analysis__uptodate_merging_prev_commit(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, PREVIOUS_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis);
+}
+
+void test_merge_analysis__unborn(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+ git_buf master = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_joinpath(&master, git_repository_path(repo), "refs/heads/master"));
+ cl_must_pass(p_unlink(git_buf_cstr(&master)));
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, NOFASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD|GIT_MERGE_ANALYSIS_UNBORN, merge_analysis);
+
+ git_buf_dispose(&master);
+}
+
+void test_merge_analysis__fastforward_with_config_noff(void)
+{
+ git_config *config;
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ cl_git_pass(git_repository_config(&config, repo));
+ cl_git_pass(git_config_set_string(config, "merge.ff", "false"));
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, FASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL|GIT_MERGE_ANALYSIS_FASTFORWARD, merge_analysis);
+
+ cl_assert_equal_i(GIT_MERGE_PREFERENCE_NO_FASTFORWARD, (merge_pref & GIT_MERGE_PREFERENCE_NO_FASTFORWARD));
+
+ git_config_free(config);
+}
+
+void test_merge_analysis__no_fastforward_with_config_ffonly(void)
+{
+ git_config *config;
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ cl_git_pass(git_repository_config(&config, repo));
+ cl_git_pass(git_config_set_string(config, "merge.ff", "only"));
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NULL, NOFASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis);
+
+ cl_assert_equal_i(GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY, (merge_pref & GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY));
+
+ git_config_free(config);
+}
+
+void test_merge_analysis__between_uptodate_refs(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ analysis_from_branch(&merge_analysis, &merge_pref, NOFASTFORWARD_BRANCH, PREVIOUS_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis);
+}
+
+void test_merge_analysis__between_noff_refs(void)
+{
+ git_merge_analysis_t merge_analysis;
+ git_merge_preference_t merge_pref;
+
+ analysis_from_branch(&merge_analysis, &merge_pref, "branch", FASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis);
+}
#include "merge_helpers.h"
#include "conflict_data.h"
#include "refs.h"
-#include "fileops.h"
+#include "futils.h"
#include "diff_xdiff.h"
#define TEST_REPO_PATH "merge-resolve"
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "refs.h"
#include "tree.h"
#include "merge_helpers.h"
return 0;
for (i = 0; i < expected_len; i++) {
- git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path);
+ git_blob_create_from_workdir(&actual_oid, repo, expected[i].path);
git_oid_fromstr(&expected_oid, expected[i].oid_str);
if (git_oid_cmp(&actual_oid, &expected_oid) != 0)
struct merge_index_with_status ancestor;
struct merge_index_with_status ours;
struct merge_index_with_status theirs;
- git_merge_diff_type_t change_type;
+ git_merge_diff_t change_type;
};
int merge_trees_from_branches(
#include "git2/merge.h"
#include "buffer.h"
#include "merge.h"
-#include "fileops.h"
+#include "futils.h"
#include "../merge_helpers.h"
#include "../conflict_data.h"
#include "buffer.h"
#include "merge.h"
#include "../merge_helpers.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
#include "buffer.h"
#include "merge.h"
#include "../merge_helpers.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
cl_assert(merge_test_index(index, merge_index_entries, 7));
git_index_free(index);
}
+
+void test_merge_trees_renames__cache_recomputation(void)
+{
+ git_oid blob, binary, ancestor_oid, theirs_oid, ours_oid;
+ git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
+ git_buf path = GIT_BUF_INIT;
+ git_treebuilder *builder;
+ git_tree *ancestor_tree, *their_tree, *our_tree;
+ git_index *index;
+ size_t blob_size;
+ void *data;
+ size_t i;
+
+ cl_git_pass(git_oid_fromstr(&blob, "a2d8d1824c68541cca94ffb90f79291eba495921"));
+
+ /*
+ * Create a 50MB blob that consists of NUL bytes only. It is important
+ * that this blob is of a special format, most importantly it cannot
+ * contain more than four non-consecutive newlines or NUL bytes. This
+ * is because of git_hashsig's inner workings where all files with less
+ * than four "lines" are deemed to small.
+ */
+ blob_size = 50 * 1024 * 1024;
+ cl_assert(data = git__calloc(blob_size, 1));
+ cl_git_pass(git_blob_create_from_buffer(&binary, repo, data, blob_size));
+
+ /*
+ * Create the common ancestor, which has 1000 dummy blobs and the binary
+ * blob. The dummy blobs serve as potential rename targets for the
+ * dummy blob.
+ */
+ cl_git_pass(git_treebuilder_new(&builder, repo, NULL));
+ for (i = 0; i < 1000; i++) {
+ cl_git_pass(git_buf_printf(&path, "%"PRIuZ".txt", i));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, path.ptr, &blob, GIT_FILEMODE_BLOB));
+ git_buf_clear(&path);
+ }
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "original.bin", &binary, GIT_FILEMODE_BLOB));
+ cl_git_pass(git_treebuilder_write(&ancestor_oid, builder));
+
+ /* We now the binary blob in our tree. */
+ cl_git_pass(git_treebuilder_remove(builder, "original.bin"));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "renamed.bin", &binary, GIT_FILEMODE_BLOB));
+ cl_git_pass(git_treebuilder_write(&ours_oid, builder));
+
+ git_treebuilder_free(builder);
+
+ /* And move everything into a subdirectory in their tree. */
+ cl_git_pass(git_treebuilder_new(&builder, repo, NULL));
+ cl_git_pass(git_treebuilder_insert(NULL, builder, "subdir", &ancestor_oid, GIT_FILEMODE_TREE));
+ cl_git_pass(git_treebuilder_write(&theirs_oid, builder));
+
+ /*
+ * Now merge ancestor, ours and theirs. As `git_hashsig` refuses to
+ * create a hash signature for the 50MB binary file, we historically
+ * didn't cache the hashsig computation for it. As a result, we now
+ * started looking up the 50MB blob and scanning it at least 1000
+ * times, which takes a long time.
+ *
+ * The number of 1000 blobs is chosen in such a way that it's
+ * noticeable when the bug creeps in again, as it takes around 12
+ * minutes on my machine to compute the following merge.
+ */
+ opts.target_limit = 5000;
+ cl_git_pass(git_tree_lookup(&ancestor_tree, repo, &ancestor_oid));
+ cl_git_pass(git_tree_lookup(&their_tree, repo, &theirs_oid));
+ cl_git_pass(git_tree_lookup(&our_tree, repo, &ours_oid));
+ cl_git_pass(git_merge_trees(&index, repo, ancestor_tree, our_tree, their_tree, &opts));
+
+ git_treebuilder_free(builder);
+ git_buf_dispose(&path);
+ git_index_free(index);
+ git_tree_free(ancestor_tree);
+ git_tree_free(their_tree);
+ git_tree_free(our_tree);
+ git__free(data);
+}
#include "merge.h"
#include "../merge_helpers.h"
#include "refs.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/sys/index.h"
static git_repository *repo;
#include "buffer.h"
#include "merge.h"
#include "../merge_helpers.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
+++ /dev/null
-#include "clar_libgit2.h"
-#include "git2/repository.h"
-#include "git2/merge.h"
-#include "git2/annotated_commit.h"
-#include "git2/sys/index.h"
-#include "merge.h"
-#include "../merge_helpers.h"
-#include "refs.h"
-#include "posix.h"
-
-static git_repository *repo;
-static git_index *repo_index;
-
-#define TEST_REPO_PATH "merge-resolve"
-#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
-
-#define UPTODATE_BRANCH "master"
-#define PREVIOUS_BRANCH "previous"
-
-#define FASTFORWARD_BRANCH "ff_branch"
-#define FASTFORWARD_ID "fd89f8cffb663ac89095a0f9764902e93ceaca6a"
-
-#define NOFASTFORWARD_BRANCH "branch"
-#define NOFASTFORWARD_ID "7cb63eed597130ba4abb87b3e544b85021905520"
-
-
-/* Fixture setup and teardown */
-void test_merge_workdir_analysis__initialize(void)
-{
- repo = cl_git_sandbox_init(TEST_REPO_PATH);
- git_repository_index(&repo_index, repo);
-}
-
-void test_merge_workdir_analysis__cleanup(void)
-{
- git_index_free(repo_index);
- cl_git_sandbox_cleanup();
-}
-
-static void analysis_from_branch(
- git_merge_analysis_t *merge_analysis,
- git_merge_preference_t *merge_pref,
- const char *our_branchname,
- const char *their_branchname)
-{
- git_buf our_refname = GIT_BUF_INIT;
- git_buf their_refname = GIT_BUF_INIT;
- git_reference *our_ref;
- git_reference *their_ref;
- git_annotated_commit *their_head;
-
- if (our_branchname != NULL) {
- cl_git_pass(git_buf_printf(&our_refname, "%s%s", GIT_REFS_HEADS_DIR, our_branchname));
- cl_git_pass(git_reference_lookup(&our_ref, repo, git_buf_cstr(&our_refname)));
- } else {
- cl_git_pass(git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE));
- }
-
- cl_git_pass(git_buf_printf(&their_refname, "%s%s", GIT_REFS_HEADS_DIR, their_branchname));
-
- cl_git_pass(git_reference_lookup(&their_ref, repo, git_buf_cstr(&their_refname)));
- cl_git_pass(git_annotated_commit_from_ref(&their_head, repo, their_ref));
-
- cl_git_pass(git_merge_analysis_for_ref(merge_analysis, merge_pref, repo, our_ref, (const git_annotated_commit **)&their_head, 1));
-
- git_buf_dispose(&our_refname);
- git_buf_dispose(&their_refname);
- git_annotated_commit_free(their_head);
- git_reference_free(our_ref);
- git_reference_free(their_ref);
-}
-
-void test_merge_workdir_analysis__fastforward(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, FASTFORWARD_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL|GIT_MERGE_ANALYSIS_FASTFORWARD, merge_analysis);
-}
-
-void test_merge_workdir_analysis__no_fastforward(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, NOFASTFORWARD_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis);
-}
-
-void test_merge_workdir_analysis__uptodate(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, UPTODATE_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis);
-}
-
-void test_merge_workdir_analysis__uptodate_merging_prev_commit(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, PREVIOUS_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis);
-}
-
-void test_merge_workdir_analysis__unborn(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
- git_buf master = GIT_BUF_INIT;
-
- git_buf_joinpath(&master, git_repository_path(repo), "refs/heads/master");
- p_unlink(git_buf_cstr(&master));
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, NOFASTFORWARD_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD|GIT_MERGE_ANALYSIS_UNBORN, merge_analysis);
-
- git_buf_dispose(&master);
-}
-
-void test_merge_workdir_analysis__fastforward_with_config_noff(void)
-{
- git_config *config;
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- git_repository_config(&config, repo);
- git_config_set_string(config, "merge.ff", "false");
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, FASTFORWARD_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL|GIT_MERGE_ANALYSIS_FASTFORWARD, merge_analysis);
-
- cl_assert_equal_i(GIT_MERGE_PREFERENCE_NO_FASTFORWARD, (merge_pref & GIT_MERGE_PREFERENCE_NO_FASTFORWARD));
-}
-
-void test_merge_workdir_analysis__no_fastforward_with_config_ffonly(void)
-{
- git_config *config;
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- git_repository_config(&config, repo);
- git_config_set_string(config, "merge.ff", "only");
-
- analysis_from_branch(&merge_analysis, &merge_pref, NULL, NOFASTFORWARD_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis);
-
- cl_assert_equal_i(GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY, (merge_pref & GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY));
-}
-
-void test_merge_workdir_analysis__between_uptodate_refs(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- analysis_from_branch(&merge_analysis, &merge_pref, NOFASTFORWARD_BRANCH, PREVIOUS_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis);
-}
-
-void test_merge_workdir_analysis__between_noff_refs(void)
-{
- git_merge_analysis_t merge_analysis;
- git_merge_preference_t merge_pref;
-
- analysis_from_branch(&merge_analysis, &merge_pref, "branch", FASTFORWARD_BRANCH);
- cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis);
-}
#include "buffer.h"
#include "merge.h"
#include "../merge_helpers.h"
-#include "fileops.h"
+#include "futils.h"
#include "refs.h"
static git_repository *repo;
#include "git2/merge.h"
#include "merge.h"
#include "refs.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
static git_index *repo_index;
#include "../merge_helpers.h"
#include "../conflict_data.h"
#include "refs.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
static git_index *repo_index;
#include "merge.h"
#include "../merge_helpers.h"
#include "refs.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
static git_index *repo_index;
void test_network_cred__stock_userpass_validates_args(void)
{
- git_cred_userpass_payload payload = {0};
+ git_credential_userpass_payload payload = {0};
- cl_git_fail(git_cred_userpass(NULL, NULL, NULL, 0, NULL));
+ cl_git_fail(git_credential_userpass(NULL, NULL, NULL, 0, NULL));
payload.username = "user";
- cl_git_fail(git_cred_userpass(NULL, NULL, NULL, 0, &payload));
+ cl_git_fail(git_credential_userpass(NULL, NULL, NULL, 0, &payload));
payload.username = NULL;
payload.username = "pass";
- cl_git_fail(git_cred_userpass(NULL, NULL, NULL, 0, &payload));
+ cl_git_fail(git_credential_userpass(NULL, NULL, NULL, 0, &payload));
}
void test_network_cred__stock_userpass_validates_that_method_is_allowed(void)
{
- git_cred *cred;
- git_cred_userpass_payload payload = {"user", "pass"};
+ git_credential *cred;
+ git_credential_userpass_payload payload = {"user", "pass"};
- cl_git_fail(git_cred_userpass(&cred, NULL, NULL, 0, &payload));
- cl_git_pass(git_cred_userpass(&cred, NULL, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload));
- cred->free(cred);
+ cl_git_fail(git_credential_userpass(&cred, NULL, NULL, 0, &payload));
+ cl_git_pass(git_credential_userpass(&cred, NULL, NULL, GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload));
+ git_credential_free(cred);
}
void test_network_cred__stock_userpass_properly_handles_username_in_url(void)
{
- git_cred *cred;
- git_cred_userpass_plaintext *plain;
- git_cred_userpass_payload payload = {"alice", "password"};
+ git_credential *cred;
+ git_credential_userpass_payload payload = {"alice", "password"};
- cl_git_pass(git_cred_userpass(&cred, NULL, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload));
- plain = (git_cred_userpass_plaintext*)cred;
- cl_assert_equal_s(plain->username, "alice");
- cred->free(cred);
+ cl_git_pass(git_credential_userpass(&cred, NULL, NULL, GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload));
+ cl_assert_equal_s("alice", git_credential_get_username(cred));
+ git_credential_free(cred);
- cl_git_pass(git_cred_userpass(&cred, NULL, "bob", GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload));
- plain = (git_cred_userpass_plaintext*)cred;
- cl_assert_equal_s(plain->username, "alice");
- cred->free(cred);
+ cl_git_pass(git_credential_userpass(&cred, NULL, "bob", GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload));
+ cl_assert_equal_s("alice", git_credential_get_username(cred));
+ git_credential_free(cred);
payload.username = NULL;
- cl_git_pass(git_cred_userpass(&cred, NULL, "bob", GIT_CREDTYPE_USERPASS_PLAINTEXT, &payload));
- plain = (git_cred_userpass_plaintext*)cred;
- cl_assert_equal_s(plain->username, "bob");
- cred->free(cred);
+ cl_git_pass(git_credential_userpass(&cred, NULL, "bob", GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload));
+ cl_assert_equal_s("bob", git_credential_get_username(cred));
+ git_credential_free(cred);
}
static const char* tagger_email = "vicent@github.com";
static const char* tagger_message = "This is my tag.\n\nThere are many tags, but this one is mine\n";
-static int transfer_cb(const git_transfer_progress *stats, void *payload)
+static int transfer_cb(const git_indexer_progress *stats, void *payload)
{
int *callcount = (int*)payload;
GIT_UNUSED(stats);
cl_assert_equal_i(19, (int)refnames.count);
cl_assert(callcount > 0);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
git_repository_free(repo);
}
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(19, (int)refnames.count);
cl_assert(callcount > 0);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/br2"));
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(18, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/packed"));
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(17, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
git_repository_free(repo);
assert_ref_exists(repo, "refs/remotes/origin/pr/42");
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(20, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
cl_git_pass(git_config_delete_multivar(config, "remote.origin.fetch", "refs"));
cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/pull/*/head:refs/remotes/origin/pr/*"));
assert_ref_exists(repo, "refs/remotes/origin/pr/42");
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(20, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
cl_git_pass(git_config_delete_multivar(config, "remote.origin.fetch", "refs"));
cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/heads/*:refs/remotes/origin/*"));
cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL));
git_config_free(config);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
git_repository_free(repo);
}
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(19, (int)refnames.count);
cl_assert(callcount > 0);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/br2"));
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(18, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/packed"));
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(17, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
git_repository_free(repo);
cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url));
cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL));
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
cl_git_pass(git_reference_list(&refnames, repo));
cl_assert_equal_i(20, (int)refnames.count); /* 18 remote + 1 local */
cl_assert(callcount > 0);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(origin);
}
cl_git_pass(git_remote_fetch(test, NULL, &options, NULL));
cl_git_pass(git_reference_list(&refnames, repo));
- cl_assert_equal_i(32, (int)refnames.count);
- git_strarray_free(&refnames);
+ cl_assert_equal_i(33, (int)refnames.count);
+ git_strarray_dispose(&refnames);
cl_git_pass(git_remote_set_url(repo, "test_with_pushurl", cl_git_fixture_url("testrepo.git")));
cl_git_pass(git_remote_lookup(&test2, repo, "test_with_pushurl"));
cl_git_pass(git_remote_fetch(test2, NULL, &options, NULL));
cl_git_pass(git_reference_list(&refnames, repo));
- cl_assert_equal_i(44, (int)refnames.count);
+ cl_assert_equal_i(45, (int)refnames.count);
- git_strarray_free(&refnames);
+ git_strarray_dispose(&refnames);
git_remote_free(test);
git_remote_free(test2);
}
--- /dev/null
+#include "clar_libgit2.h"
+#include "net.h"
+#include "netops.h"
+
+static git_net_url source, target;
+
+void test_network_joinpath__initialize(void)
+{
+ memset(&source, 0, sizeof(source));
+ memset(&target, 0, sizeof(target));
+}
+
+void test_network_joinpath__cleanup(void)
+{
+ git_net_url_dispose(&source);
+ git_net_url_dispose(&target);
+}
+
+void test_network_joinpath__target_paths_and_queries(void)
+{
+ cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b"));
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
+ cl_assert_equal_s(target.path, "/a/b/c/d");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
+ cl_assert_equal_s(target.path, "/a/b/c/d");
+ cl_assert_equal_s(target.query, "foo");
+ git_net_url_dispose(&target);
+}
+
+void test_network_joinpath__source_query_removed(void)
+{
+ cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b?query&one&two"));
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d"));
+ cl_assert_equal_s(target.path, "/a/b/c/d");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo"));
+ cl_assert_equal_s(target.path, "/a/b/c/d");
+ cl_assert_equal_s(target.query, "foo");
+ git_net_url_dispose(&target);
+}
+
+void test_network_joinpath__source_lacks_path(void)
+{
+ cl_git_pass(git_net_url_parse(&source, "http://example.com"));
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
+ cl_assert_equal_s(target.path, "/");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, ""));
+ cl_assert_equal_s(target.path, "/");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
+ cl_assert_equal_s(target.path, "/foo/bar");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
+ cl_assert_equal_s(target.path, "/foo/bar");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+}
+
+void test_network_joinpath__source_is_slash(void)
+{
+ cl_git_pass(git_net_url_parse(&source, "http://example.com/"));
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
+ cl_assert_equal_s(target.path, "/");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, ""));
+ cl_assert_equal_s(target.path, "/");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
+ cl_assert_equal_s(target.path, "/foo/bar");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
+ cl_assert_equal_s(target.path, "/foo/bar");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+}
+
+
+void test_network_joinpath__source_has_query(void)
+{
+ cl_git_pass(git_net_url_parse(&source, "http://example.com?query"));
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/"));
+ cl_assert_equal_s(target.path, "/");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, ""));
+ cl_assert_equal_s(target.path, "/");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "asdf"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar"));
+ cl_assert_equal_s(target.path, "/foo/bar");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello"));
+ cl_assert_equal_s(target.path, "/asdf");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello"));
+ cl_assert_equal_s(target.path, "/foo/bar");
+ cl_assert_equal_s(target.query, "hello");
+ git_net_url_dispose(&target);
+}
+
+
+void test_network_joinpath__empty_query_ignored(void)
+{
+ cl_git_pass(git_net_url_parse(&source, "http://example.com/foo"));
+
+ cl_git_pass(git_net_url_joinpath(&target, &source, "/bar/baz?"));
+ cl_assert_equal_s(target.path, "/foo/bar/baz");
+ cl_assert_equal_p(target.query, NULL);
+ git_net_url_dispose(&target);
+}
--- /dev/null
+#include "clar_libgit2.h"
+#include "net.h"
+#include "netops.h"
+
+static git_net_url conndata;
+
+void test_network_redirect__initialize(void)
+{
+ memset(&conndata, 0, sizeof(conndata));
+}
+
+void test_network_redirect__cleanup(void)
+{
+ git_net_url_dispose(&conndata);
+}
+
+void test_network_redirect__redirect_http(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "http://example.com/foo/bar/baz"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "http://example.com/foo/bar/baz", "bar/baz"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/foo/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_redirect__redirect_ssl(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://example.com/foo/bar/baz"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "https://example.com/foo/bar/baz", "bar/baz"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/foo/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_redirect__redirect_leaves_root_path(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://example.com/foo/bar/baz"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "https://example.com/foo/bar/baz", "/foo/bar/baz"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_redirect__redirect_encoded_username_password(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/foo/");
+ cl_assert_equal_s(conndata.username, "user/name");
+ cl_assert_equal_s(conndata.password, "pass@word%zyx%v");
+}
+
+void test_network_redirect__redirect_cross_host_denied(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "https://bar.com/bar/baz"));
+ cl_git_fail_with(git_net_url_apply_redirect(&conndata,
+ "https://foo.com/bar/baz", NULL),
+ -1);
+}
+
+void test_network_redirect__redirect_http_downgrade_denied(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz"));
+ cl_git_fail_with(git_net_url_apply_redirect(&conndata,
+ "http://foo.com/bar/baz", NULL),
+ -1);
+}
+
+void test_network_redirect__redirect_relative(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "http://foo.com/bar/baz/biff"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "/zap/baz/biff?bam", NULL));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "foo.com");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_redirect__redirect_relative_ssl(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/baz/biff"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "/zap/baz/biff?bam", NULL));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "foo.com");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+}
+
+void test_network_redirect__service_query_no_query_params_in_location(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "/baz/info/refs", "/info/refs?service=git-upload-pack"));
+ cl_assert_equal_s(conndata.path, "/baz");
+}
+
+void test_network_redirect__service_query_with_query_params_in_location(void)
+{
+ cl_git_pass(git_net_url_parse(&conndata, "https://foo.com/bar/info/refs?service=git-upload-pack"));
+ cl_git_pass(git_net_url_apply_redirect(&conndata,
+ "/baz/info/refs?service=git-upload-pack", "/info/refs?service=git-upload-pack"));
+ cl_assert_equal_s(conndata.path, "/baz");
+}
assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/delete me", false);
assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD to me", false);
- assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false);
- assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false);
+ assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true);
+ assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true);
- assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", false);
- assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", false);
+ assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", true);
+ assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", true);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false);
+ assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false);
+ assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false);
+
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true);
git_refspec spec;
git_buf buf = GIT_BUF_INIT;
- git_refspec__parse(&spec, refspec, true);
+ cl_git_pass(git_refspec__parse(&spec, refspec, true));
cl_git_pass(git_refspec_transform(&buf, &spec, name));
cl_assert_equal_s(result, buf.ptr);
assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
}
+void test_network_refspecs__transform_loosened_star(void)
+{
+ assert_valid_transform("refs/heads/branch-*:refs/remotes/origin/branch-*", "refs/heads/branch-a", "refs/remotes/origin/branch-a");
+ assert_valid_transform("refs/heads/branch-*/head:refs/remotes/origin/branch-*/head", "refs/heads/branch-a/head", "refs/remotes/origin/branch-a/head");
+}
+
+void test_network_refspecs__transform_nested_star(void)
+{
+ assert_valid_transform("refs/heads/x*x/for-linus:refs/remotes/mine/*", "refs/heads/xbranchx/for-linus", "refs/remotes/mine/branch");
+}
+
void test_network_refspecs__no_dst(void)
{
assert_valid_transform("refs/heads/master:", "refs/heads/master", "");
git_refspec spec;
git_buf buf = GIT_BUF_INIT;
- git_refspec__parse(&spec, refspec, true);
+ cl_git_pass(git_refspec__parse(&spec, refspec, true));
cl_git_fail(git_refspec_rtransform(&buf, &spec, name));
git_buf_dispose(&buf);
cl_git_pass(git_remote_ls(&refs, &refs_len, remote));
- cl_assert_equal_i(refs_len, 28);
+ cl_assert_equal_i(refs_len, 29);
}
void test_network_remote_local__retrieve_advertised_before_connect(void)
cl_git_pass(git_remote_ls(&refs, &refs_len, remote));
- cl_assert_equal_i(refs_len, 28);
+ cl_assert_equal_i(refs_len, 29);
}
void test_network_remote_local__retrieve_advertised_references_from_spaced_repository(void)
cl_git_pass(git_remote_ls(&refs, &refs_len, remote));
- cl_assert_equal_i(refs_len, 28);
+ cl_assert_equal_i(refs_len, 29);
git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */
remote = NULL;
void test_network_remote_remotes__parsing(void)
{
+ git_buf url = GIT_BUF_INIT;
git_remote *_remote2 = NULL;
cl_assert_equal_s(git_remote_name(_remote), "test");
cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
cl_assert(git_remote_pushurl(_remote) == NULL);
- cl_assert_equal_s(git_remote__urlfordirection(_remote, GIT_DIRECTION_FETCH),
- "git://github.com/libgit2/libgit2");
- cl_assert_equal_s(git_remote__urlfordirection(_remote, GIT_DIRECTION_PUSH),
- "git://github.com/libgit2/libgit2");
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL));
+ cl_assert_equal_s(url.ptr, "git://github.com/libgit2/libgit2");
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL));
+ cl_assert_equal_s(url.ptr, "git://github.com/libgit2/libgit2");
cl_git_pass(git_remote_lookup(&_remote2, _repo, "test_with_pushurl"));
cl_assert_equal_s(git_remote_name(_remote2), "test_with_pushurl");
cl_assert_equal_s(git_remote_url(_remote2), "git://github.com/libgit2/fetchlibgit2");
cl_assert_equal_s(git_remote_pushurl(_remote2), "git://github.com/libgit2/pushlibgit2");
- cl_assert_equal_s(git_remote__urlfordirection(_remote2, GIT_DIRECTION_FETCH),
- "git://github.com/libgit2/fetchlibgit2");
- cl_assert_equal_s(git_remote__urlfordirection(_remote2, GIT_DIRECTION_PUSH),
- "git://github.com/libgit2/pushlibgit2");
+ cl_git_pass(git_remote__urlfordirection(&url, _remote2, GIT_DIRECTION_FETCH, NULL));
+ cl_assert_equal_s(url.ptr, "git://github.com/libgit2/fetchlibgit2");
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote2, GIT_DIRECTION_PUSH, NULL));
+ cl_assert_equal_s(url.ptr, "git://github.com/libgit2/pushlibgit2");
git_remote_free(_remote2);
+ git_buf_dispose(&url);
+}
+
+static int urlresolve_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
+{
+ cl_assert(strcmp(url, "git://github.com/libgit2/libgit2") == 0);
+ cl_assert(strcmp(payload, "payload") == 0);
+ cl_assert(url_resolved->size == 0);
+
+ if (direction == GIT_DIRECTION_PUSH)
+ git_buf_sets(url_resolved, "pushresolve");
+ if (direction == GIT_DIRECTION_FETCH)
+ git_buf_sets(url_resolved, "fetchresolve");
+
+ return GIT_OK;
+}
+
+void test_network_remote_remotes__urlresolve(void)
+{
+ git_buf url = GIT_BUF_INIT;
+
+ git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
+ callbacks.resolve_url = urlresolve_callback;
+ callbacks.payload = "payload";
+
+ cl_assert_equal_s(git_remote_name(_remote), "test");
+ cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
+ cl_assert(git_remote_pushurl(_remote) == NULL);
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks));
+ cl_assert_equal_s(url.ptr, "fetchresolve");
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
+ cl_assert_equal_s(url.ptr, "pushresolve");
+
+ git_buf_dispose(&url);
+}
+
+static int urlresolve_passthrough_callback(git_buf *url_resolved, const char *url, int direction, void *payload)
+{
+ GIT_UNUSED(url_resolved);
+ GIT_UNUSED(url);
+ GIT_UNUSED(direction);
+ GIT_UNUSED(payload);
+ return GIT_PASSTHROUGH;
+}
+
+void test_network_remote_remotes__urlresolve_passthrough(void)
+{
+ git_buf url = GIT_BUF_INIT;
+ const char *orig_url = "git://github.com/libgit2/libgit2";
+
+ git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
+ callbacks.resolve_url = urlresolve_passthrough_callback;
+
+ cl_assert_equal_s(git_remote_name(_remote), "test");
+ cl_assert_equal_s(git_remote_url(_remote), orig_url);
+ cl_assert(git_remote_pushurl(_remote) == NULL);
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks));
+ cl_assert_equal_s(url.ptr, orig_url);
+
+ cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks));
+ cl_assert_equal_s(url.ptr, orig_url);
+
+ git_buf_dispose(&url);
}
void test_network_remote_remotes__pushurl(void)
cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote));
cl_assert_equal_i(1, (int)array.count);
cl_assert_equal_s("+refs/heads/*:refs/remotes/test/*", array.strings[0]);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
cl_git_pass(git_remote_get_push_refspecs(&array, _remote));
cl_assert_equal_i(0, (int)array.count);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(dup);
}
cl_git_pass(git_remote_list(&list, _repo));
cl_assert(list.count == 5);
- git_strarray_free(&list);
+ git_strarray_dispose(&list);
cl_git_pass(git_repository_config(&cfg, _repo));
cl_git_pass(git_remote_list(&list, _repo));
cl_assert(list.count == 7);
- git_strarray_free(&list);
+ git_strarray_dispose(&list);
git_config_free(cfg);
}
for (i = 0; i < 3; i++) {
cl_assert_equal_s(fetch_refspecs[i], array.strings[i]);
}
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
cl_git_pass(git_remote_get_push_refspecs(&array, remote));
for (i = 0; i < 3; i++) {
cl_assert_equal_s(push_refspecs[i], array.strings[i]);
}
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
git_remote_delete(_repo, "test");
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
assert_config_entry_existence(_repo, "remote.test.fetch", false);
assert_config_entry_existence(_repo, "remote.just/renamed.fetch", true);
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
assert_config_entry_value(_repo, "branch.master.remote", "just/renamed");
}
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
assert_config_entry_value(_repo, "remote.just/renamed.fetch", "+refs/heads/*:refs/remotes/just/renamed/*");
}
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
assert_config_entry_existence(_repo, "remote.just/renamed.fetch", false);
}
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(1, problems.count);
cl_assert_equal_s("+refs/*:refs/*", problems.strings[0]);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
assert_config_entry_value(_repo, "remote.just/renamed.fetch", "+refs/*:refs/*");
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
}
void test_network_remote_rename__new_name_can_contain_dots(void)
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just.renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
assert_config_entry_existence(_repo, "remote.just.renamed.fetch", true);
}
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
cl_git_pass(git_repository_open(&another_repo, "testrepo.git"));
cl_git_pass(git_remote_lookup(&renamed, _repo, "just/renamed"));
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&underlying, _repo, "refs/remotes/test/master"));
cl_git_pass(git_reference_lookup(&underlying, _repo, "refs/remotes/just/renamed/master"));
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
/* make sure there's only one remote-tracking branch */
cl_git_pass(git_branch_iterator_new(&iter, _repo, GIT_BRANCH_REMOTE));
cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "renamed"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
cl_git_pass(git_vector_init(&refs, 2, (git_vector_cmp) git_reference_cmp));
cl_git_pass(git_branch_iterator_new(&iter, _repo, GIT_BRANCH_REMOTE));
#include "clar_libgit2.h"
-#include "netops.h"
+#include "net.h"
-static char *host, *port, *path, *user, *pass;
-static gitno_connection_data conndata;
+static git_net_url conndata;
void test_network_urlparse__initialize(void)
{
- host = port = path = user = pass = NULL;
memset(&conndata, 0, sizeof(conndata));
}
void test_network_urlparse__cleanup(void)
{
-#define FREE_AND_NULL(x) if (x) { git__free(x); x = NULL; }
- FREE_AND_NULL(host);
- FREE_AND_NULL(port);
- FREE_AND_NULL(path);
- FREE_AND_NULL(user);
- FREE_AND_NULL(pass);
-
- gitno_connection_data_free_ptrs(&conndata);
+ git_net_url_dispose(&conndata);
}
void test_network_urlparse__trivial(void)
{
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "http://example.com/resource", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "8080");
- cl_assert_equal_s(path, "/resource");
- cl_assert_equal_p(user, NULL);
- cl_assert_equal_p(pass, NULL);
+ cl_git_pass(git_net_url_parse(&conndata, "http://example.com/resource"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
void test_network_urlparse__root(void)
{
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "http://example.com/", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "8080");
- cl_assert_equal_s(path, "/");
- cl_assert_equal_p(user, NULL);
- cl_assert_equal_p(pass, NULL);
-}
-
-void test_network_urlparse__just_hostname(void)
-{
- cl_git_fail_with(GIT_EINVALIDSPEC,
- gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "http://example.com", "8080"));
-}
-
-void test_network_urlparse__encoded_password(void)
-{
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://user:pass%2fis%40bad@hostname.com:1234/", "1"));
- cl_assert_equal_s(host, "hostname.com");
- cl_assert_equal_s(port, "1234");
- cl_assert_equal_s(path, "/");
- cl_assert_equal_s(user, "user");
- cl_assert_equal_s(pass, "pass/is@bad");
-}
-
-void test_network_urlparse__user(void)
-{
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://user@example.com/resource", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "8080");
- cl_assert_equal_s(path, "/resource");
- cl_assert_equal_s(user, "user");
- cl_assert_equal_p(pass, NULL);
-}
-
-void test_network_urlparse__user_pass(void)
-{
- /* user:pass@hostname.tld/resource */
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://user:pass@example.com/resource", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "8080");
- cl_assert_equal_s(path, "/resource");
- cl_assert_equal_s(user, "user");
- cl_assert_equal_s(pass, "pass");
-}
-
-void test_network_urlparse__port(void)
-{
- /* hostname.tld:port/resource */
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://example.com:9191/resource", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "9191");
- cl_assert_equal_s(path, "/resource");
- cl_assert_equal_p(user, NULL);
- cl_assert_equal_p(pass, NULL);
-}
-
-void test_network_urlparse__user_port(void)
-{
- /* user@hostname.tld:port/resource */
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://user@example.com:9191/resource", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "9191");
- cl_assert_equal_s(path, "/resource");
- cl_assert_equal_s(user, "user");
- cl_assert_equal_p(pass, NULL);
+ cl_git_pass(git_net_url_parse(&conndata, "http://example.com/"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__user_pass_port(void)
+void test_network_urlparse__implied_root(void)
{
- /* user:pass@hostname.tld:port/resource */
- cl_git_pass(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://user:pass@example.com:9191/resource", "8080"));
- cl_assert_equal_s(host, "example.com");
- cl_assert_equal_s(port, "9191");
- cl_assert_equal_s(path, "/resource");
- cl_assert_equal_s(user, "user");
- cl_assert_equal_s(pass, "pass");
+ cl_git_pass(git_net_url_parse(&conndata, "http://example.com"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "80");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__optional_path(void)
+void test_network_urlparse__implied_root_custom_port(void)
{
- cl_git_fail(gitno_extract_url_parts(&host, &port, &path, &user, &pass,
- "https://user:pass@example.com:9191", "8080"));
-
- cl_git_pass(gitno_extract_url_parts(&host, &port, NULL, &user, &pass,
- "https://user:pass@example.com:9191", "8080"));
+ cl_git_pass(git_net_url_parse(&conndata, "http://example.com:42"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "42");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__connection_data_http(void)
+void test_network_urlparse__implied_root_empty_port(void)
{
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "http://example.com/foo/bar/baz", "bar/baz"));
+ cl_git_pass(git_net_url_parse(&conndata, "http://example.com:"));
+ cl_assert_equal_s(conndata.scheme, "http");
cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "80");
- cl_assert_equal_s(conndata.path, "/foo/");
- cl_assert_equal_p(conndata.user, NULL);
- cl_assert_equal_p(conndata.pass, NULL);
- cl_assert_equal_i(conndata.use_ssl, false);
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__connection_data_ssl(void)
+void test_network_urlparse__encoded_password(void)
{
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "https://example.com/foo/bar/baz", "bar/baz"));
- cl_assert_equal_s(conndata.host, "example.com");
- cl_assert_equal_s(conndata.port, "443");
- cl_assert_equal_s(conndata.path, "/foo/");
- cl_assert_equal_p(conndata.user, NULL);
- cl_assert_equal_p(conndata.pass, NULL);
- cl_assert_equal_i(conndata.use_ssl, true);
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass%2fis%40bad@hostname.com:1234/"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "hostname.com");
+ cl_assert_equal_s(conndata.port, "1234");
+ cl_assert_equal_s(conndata.path, "/");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass/is@bad");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__encoded_username_password(void)
+void test_network_urlparse__user(void)
{
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", "bar/baz"));
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user@example.com/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "443");
- cl_assert_equal_s(conndata.path, "/foo/");
- cl_assert_equal_s(conndata.user, "user/name");
- cl_assert_equal_s(conndata.pass, "pass@word%zyx%v");
- cl_assert_equal_i(conndata.use_ssl, true);
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__connection_data_cross_host_redirect(void)
+void test_network_urlparse__user_pass(void)
{
- conndata.host = git__strdup("bar.com");
- cl_git_fail_with(gitno_connection_data_from_url(&conndata,
- "https://foo.com/bar/baz", NULL),
- -1);
+ /* user:pass@hostname.tld/resource */
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass@example.com/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "443");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__connection_data_http_downgrade(void)
+void test_network_urlparse__port(void)
{
- conndata.use_ssl = true;
- cl_git_fail_with(gitno_connection_data_from_url(&conndata,
- "http://foo.com/bar/baz", NULL),
- -1);
+ /* hostname.tld:port/resource */
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://example.com:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-void test_network_urlparse__connection_data_relative_redirect(void)
+void test_network_urlparse__empty_port(void)
{
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "http://foo.com/bar/baz/biff", NULL));
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "/zap/baz/biff?bam", NULL));
- cl_assert_equal_s(conndata.host, "foo.com");
+ cl_git_pass(git_net_url_parse(&conndata, "http://example.com:/resource"));
+ cl_assert_equal_s(conndata.scheme, "http");
+ cl_assert_equal_s(conndata.host, "example.com");
cl_assert_equal_s(conndata.port, "80");
- cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
- cl_assert_equal_p(conndata.user, NULL);
- cl_assert_equal_p(conndata.pass, NULL);
- cl_assert_equal_i(conndata.use_ssl, false);
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_p(conndata.username, NULL);
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1);
}
-void test_network_urlparse__connection_data_relative_redirect_ssl(void)
+void test_network_urlparse__user_port(void)
{
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "https://foo.com/bar/baz/biff", NULL));
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "/zap/baz/biff?bam", NULL));
- cl_assert_equal_s(conndata.host, "foo.com");
- cl_assert_equal_s(conndata.port, "443");
- cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam");
- cl_assert_equal_p(conndata.user, NULL);
- cl_assert_equal_p(conndata.pass, NULL);
- cl_assert_equal_i(conndata.use_ssl, true);
+ /* user@hostname.tld:port/resource */
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user@example.com:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_p(conndata.password, NULL);
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
-/* Run this under valgrind */
-void test_network_urlparse__connection_data_cleanup(void)
+void test_network_urlparse__user_pass_port(void)
{
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "http://foo.com/bar/baz/biff", "baz/biff"));
- cl_git_pass(gitno_connection_data_from_url(&conndata,
- "https://foo.com/bar/baz/biff", "baz/biff"));
+ /* user:pass@hostname.tld:port/resource */
+ cl_git_pass(git_net_url_parse(&conndata,
+ "https://user:pass@example.com:9191/resource"));
+ cl_assert_equal_s(conndata.scheme, "https");
+ cl_assert_equal_s(conndata.host, "example.com");
+ cl_assert_equal_s(conndata.port, "9191");
+ cl_assert_equal_s(conndata.path, "/resource");
+ cl_assert_equal_s(conndata.username, "user");
+ cl_assert_equal_s(conndata.password, "pass");
+ cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0);
}
git_note *note;
cl_git_pass(git_oid_fromstr(&oid, "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"));
-
cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 1));
-
- git_commit_lookup(¬es_commit, _repo, ¬es_commit_oid);
-
+ cl_git_pass(git_commit_lookup(¬es_commit, _repo, ¬es_commit_oid));
cl_assert(notes_commit);
cl_git_pass(git_note_commit_read(¬e, _repo, notes_commit, &oid));
-
cl_assert_equal_s(git_note_message(note), "I decorate 4a20\n");
git_commit_free(notes_commit);
git_note *_note;
cl_git_pass(git_oid_fromstr(&target_oid, "08b041783f40edfe12bb406c9c9a8a040177c125"));
-
+
for (i = 0; i < MESSAGES_COUNT; i++) {
cl_git_pass(git_note_create(¬e_oid, _repo, "refs/notes/fanout", _sig, _sig, &target_oid, messages[i], 0));
cl_git_pass(git_note_read(&_note, _repo, "refs/notes/fanout", &target_oid));
cl_git_pass(git_note_commit_create(¬es_commit_oid, NULL, _repo, NULL, _sig, _sig, &oid, "I decorate 4a20\n", 0));
- git_commit_lookup(&existing_notes_commit, _repo, ¬es_commit_oid);
+ cl_git_pass(git_commit_lookup(&existing_notes_commit, _repo, ¬es_commit_oid));
cl_assert(existing_notes_commit);
cl_git_pass(git_oid_fromstr(&target_oid, "8496071c1b46c854b31185ea97743be6a8774479"));
cl_git_pass(git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid));
-
+
error = git_note_remove(_repo, "refs/notes/fanout", _sig, _sig, &target_oid);
cl_git_fail(error);
cl_assert_equal_i(GIT_ENOTFOUND, error);
"\xFE\xFF\x00T\x00h\x00i\x00s\x00!"
};
-static git_off_t g_crlf_raw_len[CRLF_NUM_TEST_OBJECTS] = {
+static off64_t g_crlf_raw_len[CRLF_NUM_TEST_OBJECTS] = {
-1, -1, -1, -1, -1, 17, -1, -1, 12
};
if (g_crlf_raw_len[i] < 0)
g_crlf_raw_len[i] = strlen(g_crlf_raw[i]);
- cl_git_pass(git_blob_create_frombuffer(
+ cl_git_pass(git_blob_create_from_buffer(
&g_crlf_oids[i], g_repo, g_crlf_raw[i], (size_t)g_crlf_raw_len[i]));
}
}
#include "buffer.h"
#include "posix.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
static char textual_content[] = "libgit2\n\r\n\0";
cl_git_fail_with(GIT_ENOTFOUND,
git_object_lookup(&blob, repo, &expected_id, GIT_OBJECT_ANY));
- cl_git_pass(git_blob_create_fromstream(&stream, repo, NULL));
+ cl_git_pass(git_blob_create_from_stream(&stream, repo, NULL));
for (i = 0; i < howmany; i++)
cl_git_pass(stream->write(stream, textual_content, strlen(textual_content)));
- cl_git_pass(git_blob_create_fromstream_commit(&id, stream));
+ cl_git_pass(git_blob_create_from_stream_commit(&id, stream));
cl_assert_equal_oid(&expected_id, &id);
cl_git_pass(git_object_lookup(&blob, repo, &expected_id, GIT_OBJECT_BLOB));
cl_git_pass(git_oid_fromstr(&expected_id, expected_sha));
- cl_git_pass(git_blob_create_fromstream(&stream, repo, fake_name));
+ cl_git_pass(git_blob_create_from_stream(&stream, repo, fake_name));
for (i = 0; i < howmany; i++)
cl_git_pass(stream->write(stream, textual_content, strlen(textual_content)));
- cl_git_pass(git_blob_create_fromstream_commit(&id, stream));
+ cl_git_pass(git_blob_create_from_stream_commit(&id, stream));
cl_assert_equal_oid(&expected_id, &id);
}
#include "buffer.h"
#include "posix.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
{
repo = cl_git_sandbox_init(WORKDIR);
- assert_blob_creation(WORKDIR "/test.txt", "test.txt", &git_blob_create_fromworkdir);
+ assert_blob_creation(WORKDIR "/test.txt", "test.txt", &git_blob_create_from_workdir);
}
void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolute_filepath_pointing_outside_of_the_working_directory(void)
cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL));
cl_must_pass(git_buf_puts(&full_path, "test.txt"));
- assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
+ assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_from_disk);
git_buf_dispose(&full_path);
cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_RMDIR_REMOVE_FILES));
cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL));
cl_must_pass(git_buf_puts(&full_path, "test.txt"));
- assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
+ assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_from_disk);
git_buf_dispose(&full_path);
cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_RMDIR_REMOVE_FILES));
#include "repository.h"
static git_repository *g_repo;
+static size_t cache_limit;
+static int object_type;
-void test_object_cache__initialize(void)
+void test_object_cache__initialize_cache_no_blobs(void)
{
g_repo = NULL;
+ object_type = GIT_OBJECT_BLOB;
+ cache_limit = 0;
+}
+
+void test_object_cache__initialize_cache_tiny_blobs(void)
+{
+ g_repo = NULL;
+ object_type = GIT_OBJECT_BLOB;
+ cache_limit = 10;
+}
+
+void test_object_cache__initialize_cache_all_blobs(void)
+{
+ g_repo = NULL;
+ object_type = GIT_OBJECT_BLOB;
+ cache_limit = 32767;
+}
+
+void test_object_cache__initialize_cache_no_trees(void)
+{
+ g_repo = NULL;
+ object_type = GIT_OBJECT_TREE;
+ cache_limit = 0;
}
void test_object_cache__cleanup(void)
g_repo = NULL;
git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJECT_BLOB, (size_t)0);
+ git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJECT_TREE, (size_t)4096);
+ git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJECT_COMMIT, (size_t)4096);
}
static struct {
git_object_t type;
const char *sha;
+ size_t size;
} g_data[] = {
/* HEAD */
- { GIT_OBJECT_BLOB, "a8233120f6ad708f843d861ce2b7228ec4e3dec6" }, /* README */
- { GIT_OBJECT_BLOB, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc" }, /* branch_file.txt */
- { GIT_OBJECT_BLOB, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" }, /* new.txt */
+ { GIT_OBJECT_BLOB, "a8233120f6ad708f843d861ce2b7228ec4e3dec6", 10 }, /* README */
+ { GIT_OBJECT_BLOB, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc", 8 }, /* branch_file.txt */
+ { GIT_OBJECT_BLOB, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd", 12 }, /* new.txt */
/* refs/heads/subtrees */
- { GIT_OBJECT_BLOB, "1385f264afb75a56a5bec74243be9b367ba4ca08" }, /* README */
- { GIT_OBJECT_TREE, "f1425cef211cc08caa31e7b545ffb232acb098c3" }, /* ab */
- { GIT_OBJECT_BLOB, "d6c93164c249c8000205dd4ec5cbca1b516d487f" }, /* ab/4.txt */
- { GIT_OBJECT_TREE, "9a03079b8a8ee85a0bee58bf9be3da8b62414ed4" }, /* ab/c */
- { GIT_OBJECT_BLOB, "270b8ea76056d5cad83af921837702d3e3c2924d" }, /* ab/c/3.txt */
- { GIT_OBJECT_TREE, "b6361fc6a97178d8fc8639fdeed71c775ab52593" }, /* ab/de */
- { GIT_OBJECT_BLOB, "e7b4ad382349ff96dd8199000580b9b1e2042eb0" }, /* ab/de/2.txt */
- { GIT_OBJECT_TREE, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54" }, /* ab/de/fgh */
- { GIT_OBJECT_BLOB, "1f67fc4386b2d171e0d21be1c447e12660561f9b" }, /* ab/de/fgh/1.txt */
- { GIT_OBJECT_BLOB, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, /* branch_file.txt */
- { GIT_OBJECT_BLOB, "fa49b077972391ad58037050f2a75f74e3671e92" }, /* new.txt */
+ { GIT_OBJECT_BLOB, "1385f264afb75a56a5bec74243be9b367ba4ca08", 4 }, /* README */
+ { GIT_OBJECT_TREE, "f1425cef211cc08caa31e7b545ffb232acb098c3", 90 }, /* ab */
+ { GIT_OBJECT_BLOB, "d6c93164c249c8000205dd4ec5cbca1b516d487f", 6 }, /* ab/4.txt */
+ { GIT_OBJECT_TREE, "9a03079b8a8ee85a0bee58bf9be3da8b62414ed4", 33 }, /* ab/c */
+ { GIT_OBJECT_BLOB, "270b8ea76056d5cad83af921837702d3e3c2924d", 6 }, /* ab/c/3.txt */
+ { GIT_OBJECT_TREE, "b6361fc6a97178d8fc8639fdeed71c775ab52593", 63 }, /* ab/de */
+ { GIT_OBJECT_BLOB, "e7b4ad382349ff96dd8199000580b9b1e2042eb0", 6 }, /* ab/de/2.txt */
+ { GIT_OBJECT_TREE, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54", 33 }, /* ab/de/fgh */
+ { GIT_OBJECT_BLOB, "1f67fc4386b2d171e0d21be1c447e12660561f9b", 6 }, /* ab/de/fgh/1.txt */
+ { GIT_OBJECT_BLOB, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", 3 }, /* branch_file.txt */
+ { GIT_OBJECT_BLOB, "fa49b077972391ad58037050f2a75f74e3671e92", 9 }, /* new.txt */
/* refs/heads/chomped */
- { GIT_OBJECT_BLOB, "0266163a49e280c4f5ed1e08facd36a2bd716bcf" }, /* readme.txt */
+ { GIT_OBJECT_BLOB, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", 51 }, /* readme.txt */
- { 0, NULL },
- { 0, NULL }
+ { 0, NULL, 0 },
+ { 0, NULL, 0 }
};
-void test_object_cache__cache_everything(void)
+void test_object_cache__cache_counts(void)
{
- int i, start;
+ int i, start, nonmatching = 0;
git_oid oid;
git_odb_object *odb_obj;
git_object *obj;
git_odb *odb;
- git_libgit2_opts(
- GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJECT_BLOB, (size_t)32767);
+ git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, object_type, cache_limit);
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
cl_git_pass(git_repository_odb(&odb, g_repo));
git_object_free(obj);
}
- cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects));
+ if ((g_data[i].type == object_type && g_data[i].size >= cache_limit) ||
+ (g_data[i].type != object_type && g_data[i].type == GIT_OBJECT_BLOB))
+ cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects));
+ else {
+ cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects));
+ nonmatching++;
+ }
}
- cl_assert_equal_i(i, (int)git_cache_size(&g_repo->objects) - start);
-
- git_odb_free(odb);
+ cl_assert_equal_i(nonmatching, (int)git_cache_size(&g_repo->objects) - start);
for (i = 0; g_data[i].sha != NULL; ++i) {
int count = (int)git_cache_size(&g_repo->objects);
cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects));
}
-}
-
-void test_object_cache__cache_no_blobs(void)
-{
- int i, start, nonblobs = 0;
- git_oid oid;
- git_odb_object *odb_obj;
- git_object *obj;
- git_odb *odb;
-
- git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJECT_BLOB, (size_t)0);
-
- cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
- cl_git_pass(git_repository_odb(&odb, g_repo));
-
- start = (int)git_cache_size(&g_repo->objects);
-
- for (i = 0; g_data[i].sha != NULL; ++i) {
- int count = (int)git_cache_size(&g_repo->objects);
-
- cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha));
-
- /* alternate between loading raw and parsed objects */
- if ((i & 1) == 0) {
- cl_git_pass(git_odb_read(&odb_obj, odb, &oid));
- cl_assert(g_data[i].type == git_odb_object_type(odb_obj));
- git_odb_object_free(odb_obj);
- } else {
- cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJECT_ANY));
- cl_assert(g_data[i].type == git_object_type(obj));
- git_object_free(obj);
- }
-
- if (g_data[i].type == GIT_OBJECT_BLOB)
- cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects));
- else {
- cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects));
- nonblobs++;
- }
- }
-
- cl_assert_equal_i(nonblobs, (int)git_cache_size(&g_repo->objects) - start);
git_odb_free(odb);
}
void test_object_cache__fast_thread_rush(void)
{
- int try, th, data[THREADCOUNT*2];
+ int try, th, data[THREADCOUNT];
#ifdef GIT_THREADS
- git_thread t[THREADCOUNT*2];
+ git_thread t[THREADCOUNT];
#endif
for (try = 0; try < REPEAT; ++try) {
cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
- for (th = 0; th < THREADCOUNT*2; ++th) {
+ for (th = 0; th < THREADCOUNT; ++th) {
data[th] = th;
#ifdef GIT_THREADS
cl_git_pass(
}
#ifdef GIT_THREADS
- for (th = 0; th < THREADCOUNT*2; ++th) {
+ for (th = 0; th < THREADCOUNT; ++th) {
void *rval;
cl_git_pass(git_thread_join(&t[th], &rval));
cl_assert_equal_i(th, *((int *)rval));
* tree 2b297e643c551e76cfa1f93810c50811382f9117
* author nulltoken <emeric.fermas@gmail.com> 1323847743 +0100
* committer nulltoken <emeric.fermas@gmail.com> 1323847743 +0100
- *
+ *
* Initial commit
- *
+ *
* diff --git a/test.txt b/test.txt
* new file mode 100644
* index 0000000..9daeafb
git_tree_free(tree);
}
-static void assert_commit_is_head_(git_commit *c, const char *file, int line)
+static void assert_commit_is_head_(git_commit *c, const char *file, const char *func, int line)
{
git_commit *head;
cl_git_pass(git_revparse_single((git_object **)&head, repo, "HEAD"));
- clar__assert(git_oid_equal(git_commit_id(c), git_commit_id(head)), file, line, "Commit is not the HEAD", NULL, 1);
+ clar__assert(git_oid_equal(git_commit_id(c), git_commit_id(head)), file, func, line, "Commit is not the HEAD", NULL, 1);
git_commit_free(head);
}
-#define assert_commit_is_head(C) assert_commit_is_head_((C),__FILE__,__LINE__)
+#define assert_commit_is_head(C) assert_commit_is_head_((C),__FILE__,__func__,__LINE__)
void test_object_commit_commitstagedfile__amend_commit(void)
{
#include "clar_libgit2.h"
#include "git2/odb_backend.h"
-#include "fileops.h"
+#include "futils.h"
#include "odb.h"
typedef struct object_data {
cl_assert_equal_i((int)sucessfully_found, (int)data->expected_matches);
exit:
- git_strarray_free(&tag_list);
+ git_strarray_dispose(&tag_list);
cl_git_pass(error);
}
cl_assert_equal_i((int)tag_list.count, 6);
- git_strarray_free(&tag_list);
+ git_strarray_dispose(&tag_list);
}
static const struct pattern_match_t matches[] = {
git_object_free(obj);
git_tree_free(tree);
}
+
+#define BIGFILE "bigfile"
+
+#ifdef GIT_ARCH_64
+#define BIGFILE_SIZE (off_t)4294967296
+#else
+# define BIGFILE_SIZE SIZE_MAX
+#endif
+
+void test_object_tree_read__largefile(void)
+{
+ const git_tree_entry *entry;
+ git_index_entry ie;
+ git_commit *commit;
+ git_object *object;
+ git_index *index;
+ git_tree *tree;
+ git_oid oid;
+ char *buf;
+
+ if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE"))
+ cl_skip();
+
+ cl_assert(buf = git__calloc(1, BIGFILE_SIZE));
+
+ memset(&ie, 0, sizeof(ie));
+ ie.mode = GIT_FILEMODE_BLOB;
+ ie.path = BIGFILE;
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_add_from_buffer(index, &ie, buf, BIGFILE_SIZE));
+ cl_repo_commit_from_index(&oid, g_repo, NULL, 0, BIGFILE);
+
+ cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
+ cl_git_pass(git_commit_tree(&tree, commit));
+ cl_assert(entry = git_tree_entry_byname(tree, BIGFILE));
+ cl_git_pass(git_tree_entry_to_object(&object, g_repo, entry));
+
+ git_object_free(object);
+ git_tree_free(tree);
+ git_index_free(index);
+ git_commit_free(commit);
+ git__free(buf);
+}
git_oid valid_blob_id, invalid_blob_id, valid_tree_id, invalid_tree_id;
#define assert_allowed(expr) \
- clar__assert(!(expr) == should_allow_invalid, __FILE__, __LINE__, \
+ clar__assert(!(expr) == should_allow_invalid, \
+ __FILE__, __func__, __LINE__, \
(should_allow_invalid ? \
"Expected function call to succeed: " #expr : \
"Expected function call to fail: " #expr), \
cl_assert(git_odb_exists(_odb, &_oid) == 1);
}
-void test_odb_backend_mempack__blob_create_frombuffer_succeeds(void)
+void test_odb_backend_mempack__blob_create_from_buffer_succeeds(void)
{
const char *data = "data";
- cl_git_pass(git_blob_create_frombuffer(&_oid, _repo, data, strlen(data) + 1));
+ cl_git_pass(git_blob_create_from_buffer(&_oid, _repo, data, strlen(data) + 1));
cl_assert(git_odb_exists(_odb, &_oid) == 1);
}
set_time_wayback(&before, LOOSE_BLOB_FN);
/* make sure we freshen a blob */
- cl_git_pass(git_blob_create_frombuffer(&id, repo, LOOSE_STR, CONST_STRLEN(LOOSE_STR)));
+ cl_git_pass(git_blob_create_from_buffer(&id, repo, LOOSE_STR, CONST_STRLEN(LOOSE_STR)));
cl_assert_equal_oid(&expected_id, &id);
cl_must_pass(p_lstat("testrepo.git/objects/" LOOSE_BLOB_FN, &after));
cl_git_pass(git_oid_fromstr(&expected_id, UNIQUE_BLOB_ID));
- cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
+ cl_git_pass(git_blob_create_from_buffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
cl_assert_equal_oid(&expected_id, &id);
set_time_wayback(&before, UNIQUE_BLOB_FN);
cl_assert((before.st_mode & S_IWUSR) == 0);
- cl_git_pass(git_blob_create_frombuffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
+ cl_git_pass(git_blob_create_from_buffer(&id, repo, UNIQUE_STR, CONST_STRLEN(UNIQUE_STR)));
cl_assert_equal_oid(&expected_id, &id);
cl_must_pass(p_lstat("testrepo.git/objects/" UNIQUE_BLOB_FN, &after));
#include "git2/clone.h"
#include "git2/cred_helpers.h"
#include "remote.h"
-#include "fileops.h"
+#include "futils.h"
#include "refs.h"
#define LIVE_REPO_URL "http://github.com/libgit2/TestGitRepository"
#define BB_REPO_URL "https://libgit3@bitbucket.org/libgit2/testgitrepository.git"
#define BB_REPO_URL_WITH_PASS "https://libgit3:libgit3@bitbucket.org/libgit2/testgitrepository.git"
#define BB_REPO_URL_WITH_WRONG_PASS "https://libgit3:wrong@bitbucket.org/libgit2/testgitrepository.git"
+#define GOOGLESOURCE_REPO_URL "https://chromium.googlesource.com/external/github.com/sergi/go-diff"
#define SSH_REPO_URL "ssh://github.com/libgit2/TestGitRepository"
static char *_remote_proxy_user = NULL;
static char *_remote_proxy_pass = NULL;
static char *_remote_proxy_selfsigned = NULL;
+static char *_remote_expectcontinue = NULL;
static int _orig_proxies_need_reset = 0;
static char *_orig_http_proxy = NULL;
_remote_proxy_user = cl_getenv("GITTEST_REMOTE_PROXY_USER");
_remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS");
_remote_proxy_selfsigned = cl_getenv("GITTEST_REMOTE_PROXY_SELFSIGNED");
+ _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
+
+ if (_remote_expectcontinue)
+ git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1);
_orig_proxies_need_reset = 0;
}
git__free(_remote_proxy_user);
git__free(_remote_proxy_pass);
git__free(_remote_proxy_selfsigned);
+ git__free(_remote_expectcontinue);
if (_orig_proxies_need_reset) {
cl_setenv("HTTP_PROXY", _orig_http_proxy);
(*was_called) = true;
}
-static int fetch_progress(const git_transfer_progress *stats, void *payload)
+static int fetch_progress(const git_indexer_progress *stats, void *payload)
{
bool *was_called = (bool*)payload;
GIT_UNUSED(stats);
void test_online_clone__can_checkout_a_cloned_repo(void)
{
git_buf path = GIT_BUF_INIT;
- git_reference *head;
+ git_reference *head, *remote_head;
bool checkout_progress_cb_was_called = false,
fetch_progress_cb_was_called = false;
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head));
cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
+ cl_git_pass(git_reference_lookup(&remote_head, g_repo, "refs/remotes/origin/HEAD"));
+ cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(remote_head));
+ cl_assert_equal_s("refs/remotes/origin/master", git_reference_symbolic_target(remote_head));
+
cl_assert_equal_i(true, checkout_progress_cb_was_called);
cl_assert_equal_i(true, fetch_progress_cb_was_called);
+ git_reference_free(remote_head);
git_reference_free(head);
git_buf_dispose(&path);
}
}
static int cred_failure_cb(
- git_cred **cred,
+ git_credential **cred,
const char *url,
const char *username_from_url,
unsigned int allowed_types,
cl_git_fail_with(-172, git_clone(&g_repo, _remote_url, "./foo", &g_options));
}
-static int cred_count_calls_cb(git_cred **cred, const char *url, const char *user,
+static int cred_count_calls_cb(git_credential **cred, const char *url, const char *user,
unsigned int allowed_types, void *data)
{
size_t *counter = (size_t *) data;
GIT_UNUSED(url); GIT_UNUSED(user); GIT_UNUSED(allowed_types);
- if (allowed_types == GIT_CREDTYPE_USERNAME)
- return git_cred_username_new(cred, "foo");
+ if (allowed_types == GIT_CREDENTIAL_USERNAME)
+ return git_credential_username_new(cred, "foo");
(*counter)++;
if (*counter == 3)
return GIT_EUSER;
- return git_cred_userpass_plaintext_new(cred, "foo", "bar");
+ return git_credential_userpass_plaintext_new(cred, "foo", "bar");
}
void test_online_clone__cred_callback_called_again_on_auth_failure(void)
git__free(_remote_url);
git__free(_remote_user);
- _remote_url = git__strdup("https://github.com/libgit2/non-existent");
+ _remote_url = git__strdup("https://gitlab.com/libgit2/non-existent");
_remote_user = git__strdup("libgit2test");
g_options.fetch_opts.callbacks.credentials = cred_count_calls_cb;
}
int cred_default(
- git_cred **cred,
+ git_credential **cred,
const char *url,
const char *user_from_url,
unsigned int allowed_types,
GIT_UNUSED(user_from_url);
GIT_UNUSED(payload);
- if (!(allowed_types & GIT_CREDTYPE_DEFAULT))
+ if (!(allowed_types & GIT_CREDENTIAL_DEFAULT))
return 0;
- return git_cred_default_new(cred);
+ return git_credential_default_new(cred);
}
void test_online_clone__credentials(void)
/* Remote URL environment variable must be set.
* User and password are optional.
*/
- git_cred_userpass_payload user_pass = {
+ git_credential_userpass_payload user_pass = {
_remote_user,
_remote_pass
};
if (cl_is_env_set("GITTEST_REMOTE_DEFAULT")) {
g_options.fetch_opts.callbacks.credentials = cred_default;
} else {
- g_options.fetch_opts.callbacks.credentials = git_cred_userpass;
+ g_options.fetch_opts.callbacks.credentials = git_credential_userpass;
g_options.fetch_opts.callbacks.payload = &user_pass;
}
cl_fixture_cleanup("./foo");
}
+void test_online_clone__credentials_via_custom_headers(void)
+{
+ const char *creds = "libgit3:libgit3";
+ git_buf auth = GIT_BUF_INIT;
+
+ cl_git_pass(git_buf_puts(&auth, "Authorization: Basic "));
+ cl_git_pass(git_buf_encode_base64(&auth, creds, strlen(creds)));
+ g_options.fetch_opts.custom_headers.count = 1;
+ g_options.fetch_opts.custom_headers.strings = &auth.ptr;
+
+ cl_git_pass(git_clone(&g_repo, "https://bitbucket.org/libgit2/testgitrepository.git", "./foo", &g_options));
+
+ git_buf_dispose(&auth);
+}
+
void test_online_clone__bitbucket_style(void)
{
- git_cred_userpass_payload user_pass = {
+ git_credential_userpass_payload user_pass = {
"libgit3", "libgit3"
};
- g_options.fetch_opts.callbacks.credentials = git_cred_userpass;
+ g_options.fetch_opts.callbacks.credentials = git_credential_userpass;
g_options.fetch_opts.callbacks.payload = &user_pass;
cl_git_pass(git_clone(&g_repo, BB_REPO_URL, "./foo", &g_options));
void test_online_clone__bitbucket_uses_creds_in_url(void)
{
- git_cred_userpass_payload user_pass = {
+ git_credential_userpass_payload user_pass = {
"libgit2", "wrong"
};
- g_options.fetch_opts.callbacks.credentials = git_cred_userpass;
+ g_options.fetch_opts.callbacks.credentials = git_credential_userpass;
g_options.fetch_opts.callbacks.payload = &user_pass;
/*
* Correct user and pass are in the URL; the (incorrect) creds in
- * the `git_cred_userpass_payload` should be ignored.
+ * the `git_credential_userpass_payload` should be ignored.
*/
cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_PASS, "./foo", &g_options));
git_repository_free(g_repo); g_repo = NULL;
void test_online_clone__bitbucket_falls_back_to_specified_creds(void)
{
- git_cred_userpass_payload user_pass = {
+ git_credential_userpass_payload user_pass = {
"libgit2", "libgit2"
};
- g_options.fetch_opts.callbacks.credentials = git_cred_userpass;
+ g_options.fetch_opts.callbacks.credentials = git_credential_userpass;
g_options.fetch_opts.callbacks.payload = &user_pass;
/*
/*
* Incorrect user and pass are in the URL; the (correct) creds in
- * the `git_cred_userpass_payload` should be used as a fallback.
+ * the `git_credential_userpass_payload` should be used as a fallback.
*/
cl_git_pass(git_clone(&g_repo, BB_REPO_URL_WITH_WRONG_PASS, "./foo", &g_options));
git_repository_free(g_repo); g_repo = NULL;
cl_fixture_cleanup("./foo");
}
-static int cancel_at_half(const git_transfer_progress *stats, void *payload)
+void test_online_clone__googlesource(void)
+{
+ cl_git_pass(git_clone(&g_repo, GOOGLESOURCE_REPO_URL, "./foo", &g_options));
+ git_repository_free(g_repo); g_repo = NULL;
+ cl_fixture_cleanup("./foo");
+}
+
+static int cancel_at_half(const git_indexer_progress *stats, void *payload)
{
GIT_UNUSED(payload);
{
g_options.fetch_opts.callbacks.transfer_progress = cancel_at_half;
- cl_git_fail_with(
- git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options), 4321);
+ cl_git_fail_with(4321,
+ git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
}
-static int cred_cb(git_cred **cred, const char *url, const char *user_from_url,
+static int cred_cb(git_credential **cred, const char *url, const char *user_from_url,
unsigned int allowed_types, void *payload)
{
GIT_UNUSED(url); GIT_UNUSED(user_from_url); GIT_UNUSED(payload);
- if (allowed_types & GIT_CREDTYPE_USERNAME)
- return git_cred_username_new(cred, _remote_user);
+ if (allowed_types & GIT_CREDENTIAL_USERNAME)
+ return git_credential_username_new(cred, _remote_user);
- if (allowed_types & GIT_CREDTYPE_SSH_KEY)
- return git_cred_ssh_key_new(cred,
+ if (allowed_types & GIT_CREDENTIAL_SSH_KEY)
+ return git_credential_ssh_key_new(cred,
_remote_user, _remote_ssh_pubkey,
_remote_ssh_privkey, _remote_ssh_passphrase);
return -1;
}
-static int check_ssh_auth_methods(git_cred **cred, const char *url, const char *username_from_url,
+static int check_ssh_auth_methods(git_credential **cred, const char *url, const char *username_from_url,
unsigned int allowed_types, void *data)
{
int *with_user = (int *) data;
GIT_UNUSED(cred); GIT_UNUSED(url); GIT_UNUSED(username_from_url); GIT_UNUSED(data);
if (!*with_user)
- cl_assert_equal_i(GIT_CREDTYPE_USERNAME, allowed_types);
+ cl_assert_equal_i(GIT_CREDENTIAL_USERNAME, allowed_types);
else
- cl_assert(!(allowed_types & GIT_CREDTYPE_USERNAME));
+ cl_assert(!(allowed_types & GIT_CREDENTIAL_USERNAME));
return GIT_EUSER;
}
cl_git_pass(git_clone(&g_repo, _remote_url, "./foo", &g_options));
}
-static int cred_foo_bar(git_cred **cred, const char *url, const char *username_from_url,
+static int cred_foo_bar(git_credential **cred, const char *url, const char *username_from_url,
unsigned int allowed_types, void *data)
{
GIT_UNUSED(url); GIT_UNUSED(username_from_url); GIT_UNUSED(allowed_types); GIT_UNUSED(data);
- return git_cred_userpass_plaintext_new(cred, "foo", "bar");
+ return git_credential_userpass_plaintext_new(cred, "foo", "bar");
}
void test_online_clone__ssh_cannot_change_username(void)
return buf;
}
-static int ssh_memory_cred_cb(git_cred **cred, const char *url, const char *user_from_url,
+static int ssh_memory_cred_cb(git_credential **cred, const char *url, const char *user_from_url,
unsigned int allowed_types, void *payload)
{
GIT_UNUSED(url); GIT_UNUSED(user_from_url); GIT_UNUSED(payload);
- if (allowed_types & GIT_CREDTYPE_USERNAME)
- return git_cred_username_new(cred, _remote_user);
+ if (allowed_types & GIT_CREDENTIAL_USERNAME)
+ return git_credential_username_new(cred, _remote_user);
- if (allowed_types & GIT_CREDTYPE_SSH_KEY)
+ if (allowed_types & GIT_CREDENTIAL_SSH_KEY)
{
char *pubkey = read_key_file(_remote_ssh_pubkey);
char *privkey = read_key_file(_remote_ssh_privkey);
- int ret = git_cred_ssh_key_memory_new(cred, _remote_user, pubkey, privkey, _remote_ssh_passphrase);
+ int ret = git_credential_ssh_key_memory_new(cred, _remote_user, pubkey, privkey, _remote_ssh_passphrase);
if (privkey)
free(privkey);
cl_git_pass(git_clone(&g_repo, _remote_url, "./foo", &g_options));
}
-void test_online_clone__url_with_no_path_returns_EINVALIDSPEC(void)
-{
- cl_git_fail_with(git_clone(&g_repo, "http://github.com", "./foo", &g_options),
- GIT_EINVALIDSPEC);
-}
-
static int fail_certificate_check(git_cert *cert, int valid, const char *host, void *payload)
{
GIT_UNUSED(cert);
}
static int called_proxy_creds;
-static int proxy_cred_cb(git_cred **out, const char *url, const char *username, unsigned int allowed, void *payload)
+static int proxy_cred_cb(git_credential **out, const char *url, const char *username, unsigned int allowed, void *payload)
{
GIT_UNUSED(url);
GIT_UNUSED(username);
GIT_UNUSED(payload);
called_proxy_creds = 1;
- return git_cred_userpass_plaintext_new(out, _remote_proxy_user, _remote_proxy_pass);
+ return git_credential_userpass_plaintext_new(out, _remote_proxy_user, _remote_proxy_pass);
}
static int proxy_cert_cb(git_cert *cert, int valid, const char *host, void *payload)
cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
}
+
+void test_online_clone__proxy_cred_callback_after_failed_url_creds(void)
+{
+ git_buf url = GIT_BUF_INIT;
+
+ if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
+ cl_skip();
+
+ cl_git_pass(git_buf_printf(&url, "%s://invalid_user_name:INVALID_pass_WORD@%s/",
+ _remote_proxy_scheme ? _remote_proxy_scheme : "http",
+ _remote_proxy_host));
+
+ g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
+ g_options.fetch_opts.proxy_opts.url = url.ptr;
+ g_options.fetch_opts.proxy_opts.credentials = proxy_cred_cb;
+ g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
+ called_proxy_creds = 0;
+ cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
+ cl_assert(called_proxy_creds);
+
+ git_buf_dispose(&url);
+}
+
+void test_online_clone__azurerepos(void)
+{
+ cl_git_pass(git_clone(&g_repo, "https://libgit2@dev.azure.com/libgit2/test/_git/test", "./foo", &g_options));
+ cl_assert(git_path_exists("./foo/master.txt"));
+}
+
+void test_online_clone__path_whitespace(void)
+{
+ cl_git_pass(git_clone(&g_repo, "https://libgit2@dev.azure.com/libgit2/test/_git/spaces%20in%20the%20name", "./foo", &g_options));
+ cl_assert(git_path_exists("./foo/master.txt"));
+}
return 0;
}
-static int progress(const git_transfer_progress *stats, void *payload)
+static int progress(const git_indexer_progress *stats, void *payload)
{
size_t *bytes_received = (size_t *)payload;
*bytes_received = stats->received_bytes;
cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
cl_git_pass(git_remote_download(remote, NULL, NULL));
git_remote_disconnect(remote);
-
+
git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL);
cl_git_pass(git_remote_download(remote, NULL, NULL));
git_remote_disconnect(remote);
-
+
git_remote_free(remote);
}
-static int transferProgressCallback(const git_transfer_progress *stats, void *payload)
+static int transferProgressCallback(const git_indexer_progress *stats, void *payload)
{
bool *invoked = (bool *)payload;
git_repository_free(_repository);
}
-static int cancel_at_half(const git_transfer_progress *stats, void *payload)
+static int cancel_at_half(const git_indexer_progress *stats, void *payload)
{
GIT_UNUSED(payload);
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "fetchhead.h"
#include "../fetchhead/fetchhead_data.h"
#include "git2/clone.h"
cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
}
-static int count_references(void)
+static size_t count_references(void)
{
git_strarray array;
- int refs;
+ size_t refs;
cl_git_pass(git_reference_list(&array, g_repo));
refs = array.count;
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
return refs;
}
void test_online_fetchhead__explicit_dst_refspec_creates_branch(void)
{
git_reference *ref;
- int refs;
+ size_t refs;
fetchhead_test_clone();
refs = count_references();
void test_online_fetchhead__empty_dst_refspec_creates_no_branch(void)
{
git_reference *ref;
- int refs;
+ size_t refs;
fetchhead_test_clone();
refs = count_references();
void test_online_fetchhead__colon_only_dst_refspec_creates_no_branch(void)
{
- int refs;
+ size_t refs;
fetchhead_test_clone();
refs = count_references();
cl_assert_equal_i(refs, count_references());
}
+
+void test_online_fetchhead__creds_get_stripped(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+ git_remote *remote;
+
+ cl_git_pass(git_repository_init(&g_repo, "./foo", 0));
+ cl_git_pass(git_remote_create_anonymous(&remote, g_repo, "https://foo:bar@github.com/libgit2/TestGitRepository"));
+ cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
+
+ cl_git_pass(git_futils_readbuffer(&buf, "./foo/.git/FETCH_HEAD"));
+ cl_assert_equal_s(buf.ptr,
+ "49322bb17d3acc9146f98c97d078513228bbf3c0\t\thttps://github.com/libgit2/TestGitRepository\n");
+
+ git_remote_free(remote);
+ git_buf_dispose(&buf);
+}
static char *_remote_ssh_passphrase = NULL;
static char *_remote_default = NULL;
+static char *_remote_expectcontinue = NULL;
-static int cred_acquire_cb(git_cred **, const char *, const char *, unsigned int, void *);
+static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *);
static git_remote *_remote;
static record_callbacks_data _record_cbs_data = {{ 0 }};
static git_oid _tag_tag;
static int cred_acquire_cb(
- git_cred **cred,
+ git_credential **cred,
const char *url,
const char *user_from_url,
unsigned int allowed_types,
GIT_UNUSED(user_from_url);
GIT_UNUSED(payload);
- if (GIT_CREDTYPE_USERNAME & allowed_types) {
+ if (GIT_CREDENTIAL_USERNAME & allowed_types) {
if (!_remote_user) {
printf("GITTEST_REMOTE_USER must be set\n");
return -1;
}
- return git_cred_username_new(cred, _remote_user);
+ return git_credential_username_new(cred, _remote_user);
}
- if (GIT_CREDTYPE_DEFAULT & allowed_types) {
+ if (GIT_CREDENTIAL_DEFAULT & allowed_types) {
if (!_remote_default) {
printf("GITTEST_REMOTE_DEFAULT must be set to use NTLM/Negotiate credentials\n");
return -1;
}
- return git_cred_default_new(cred);
+ return git_credential_default_new(cred);
}
- if (GIT_CREDTYPE_SSH_KEY & allowed_types) {
+ if (GIT_CREDENTIAL_SSH_KEY & allowed_types) {
if (!_remote_user || !_remote_ssh_pubkey || !_remote_ssh_key || !_remote_ssh_passphrase) {
printf("GITTEST_REMOTE_USER, GITTEST_REMOTE_SSH_PUBKEY, GITTEST_REMOTE_SSH_KEY and GITTEST_REMOTE_SSH_PASSPHRASE must be set\n");
return -1;
}
- return git_cred_ssh_key_new(cred, _remote_user, _remote_ssh_pubkey, _remote_ssh_key, _remote_ssh_passphrase);
+ return git_credential_ssh_key_new(cred, _remote_user, _remote_ssh_pubkey, _remote_ssh_key, _remote_ssh_passphrase);
}
- if (GIT_CREDTYPE_USERPASS_PLAINTEXT & allowed_types) {
+ if (GIT_CREDENTIAL_USERPASS_PLAINTEXT & allowed_types) {
if (!_remote_user || !_remote_pass) {
printf("GITTEST_REMOTE_USER and GITTEST_REMOTE_PASS must be set\n");
return -1;
}
- return git_cred_userpass_plaintext_new(cred, _remote_user, _remote_pass);
+ return git_credential_userpass_plaintext_new(cred, _remote_user, _remote_pass);
}
return -1;
_remote_ssh_pubkey = cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
_remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
_remote_default = cl_getenv("GITTEST_REMOTE_DEFAULT");
+ _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
_remote = NULL;
/* Skip the test if we're missing the remote URL */
if (!_remote_url)
cl_skip();
+ if (_remote_expectcontinue)
+ git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1);
+
cl_git_pass(git_remote_create(&_remote, _repo, "test", _remote_url));
record_callbacks_data_clear(&_record_cbs_data);
git__free(_remote_ssh_pubkey);
git__free(_remote_ssh_passphrase);
git__free(_remote_default);
+ git__free(_remote_expectcontinue);
/* Freed by cl_git_sandbox_cleanup */
_repo = NULL;
+ git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 0);
+
record_callbacks_data_clear(&_record_cbs_data);
cl_fixture_cleanup("testrepo.git");
* @param data pointer to a record_callbacks_data instance
*/
#define RECORD_CALLBACKS_INIT(data) \
- { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, data }
+ { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, NULL, NULL, data, NULL }
typedef struct {
char *name;
}
cl_assert_equal_i(1, count);
- git_strarray_free(&refs);
+ git_strarray_dispose(&refs);
cl_git_pass(git_remote_lookup(&remote, repo, "origin"));
cl_git_pass(git_remote_get_fetch_refspecs(&refs, remote));
cl_assert_equal_i(1, refs.count);
cl_assert_equal_s(REFSPEC, refs.strings[0]);
- git_strarray_free(&refs);
+ git_strarray_dispose(&refs);
git_remote_free(remote);
git_repository_free(repo);
}
--- /dev/null
+#include "clar_libgit2.h"
+#include "mwindow.h"
+#include "global.h"
+
+#include <git2.h>
+#include "git2/sys/commit.h"
+#include "git2/sys/mempack.h"
+
+static size_t expected_open_mwindow_files = 0;
+static size_t original_mwindow_file_limit = 0;
+
+extern git_mwindow_ctl git_mwindow__mem_ctl;
+
+void test_pack_filelimit__initialize_tiny(void)
+{
+ expected_open_mwindow_files = 1;
+ cl_git_pass(git_libgit2_opts(GIT_OPT_GET_MWINDOW_FILE_LIMIT, &original_mwindow_file_limit));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, expected_open_mwindow_files));
+}
+
+void test_pack_filelimit__initialize_medium(void)
+{
+ expected_open_mwindow_files = 10;
+ cl_git_pass(git_libgit2_opts(GIT_OPT_GET_MWINDOW_FILE_LIMIT, &original_mwindow_file_limit));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, expected_open_mwindow_files));
+}
+
+void test_pack_filelimit__initialize_unlimited(void)
+{
+ expected_open_mwindow_files = 15;
+ cl_git_pass(git_libgit2_opts(GIT_OPT_GET_MWINDOW_FILE_LIMIT, &original_mwindow_file_limit));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, 0));
+}
+
+void test_pack_filelimit__cleanup(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, original_mwindow_file_limit));
+
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), "repo.git"));
+ cl_fixture_cleanup(path.ptr);
+ git_buf_dispose(&path);
+}
+
+/*
+ * Create a packfile with one commit, one tree, and two blobs. The first blob
+ * (README.md) has the same content in all commits, but the second one
+ * (file.txt) has a different content in each commit.
+ */
+void create_packfile_commit(
+ git_repository *repo,
+ git_oid *out_commit_id,
+ git_oid *parent_id,
+ size_t commit_index,
+ size_t commit_count)
+{
+ git_buf file_contents = GIT_BUF_INIT;
+ git_treebuilder *treebuilder;
+ git_packbuilder *packbuilder;
+ git_signature *s;
+ git_oid oid, tree_id, commit_id;
+ const git_oid *parents[] = { parent_id };
+ size_t parent_count = parent_id ? 1 : 0;
+
+ cl_git_pass(git_treebuilder_new(&treebuilder, repo, NULL));
+
+ cl_git_pass(git_blob_create_from_buffer(&oid, repo, "", 0));
+ cl_git_pass(git_treebuilder_insert(NULL, treebuilder, "README.md", &oid, 0100644));
+
+ cl_git_pass(git_buf_printf(&file_contents, "Commit %zd/%zd", commit_index, commit_count));
+ cl_git_pass(git_blob_create_from_buffer(&oid, repo, file_contents.ptr, file_contents.size));
+ cl_git_pass(git_treebuilder_insert(NULL, treebuilder, "file.txt", &oid, 0100644));
+
+ cl_git_pass(git_treebuilder_write(&tree_id, treebuilder));
+ cl_git_pass(git_signature_now(&s, "alice", "alice@example.com"));
+ cl_git_pass(git_commit_create_from_ids(&commit_id, repo, "refs/heads/master", s, s,
+ NULL, file_contents.ptr, &tree_id, parent_count, parents));
+
+ cl_git_pass(git_packbuilder_new(&packbuilder, repo));
+ cl_git_pass(git_packbuilder_insert_commit(packbuilder, &commit_id));
+ cl_git_pass(git_packbuilder_write(packbuilder, NULL, 0, NULL, NULL));
+
+ cl_git_pass(git_oid_cpy(out_commit_id, &commit_id));
+
+ git_buf_dispose(&file_contents);
+ git_treebuilder_free(treebuilder);
+ git_packbuilder_free(packbuilder);
+ git_signature_free(s);
+}
+
+void test_pack_filelimit__open_repo_with_multiple_packfiles(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_mwindow_ctl *ctl = &git_mwindow__mem_ctl;
+ git_repository *repo;
+ git_revwalk *walk;
+ git_oid id, *parent_id = NULL;
+ size_t i;
+ const size_t commit_count = 16;
+ unsigned int open_windows;
+
+ /*
+ * Create a repository and populate it with 16 commits, each in its own
+ * packfile.
+ */
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), "repo.git"));
+ cl_git_pass(git_repository_init(&repo, path.ptr, true));
+ for (i = 0; i < commit_count; ++i) {
+ create_packfile_commit(repo, &id, parent_id, i + 1, commit_count);
+ parent_id = &id;
+ }
+
+ cl_git_pass(git_revwalk_new(&walk, repo));
+ cl_git_pass(git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL));
+ cl_git_pass(git_revwalk_push_ref(walk, "refs/heads/master"));
+
+ /* Walking the repository requires eventually opening each of the packfiles. */
+ i = 0;
+ while (git_revwalk_next(&id, walk) == 0)
+ ++i;
+ cl_assert_equal_i(commit_count, i);
+
+ cl_git_pass(git_mutex_lock(&git__mwindow_mutex));
+ /*
+ * Adding an assert while holding a lock will cause the whole process to
+ * deadlock. Copy the value and do the assert after releasing the lock.
+ */
+ open_windows = ctl->open_windows;
+ cl_git_pass(git_mutex_unlock(&git__mwindow_mutex));
+
+ cl_assert_equal_i(expected_open_mwindow_files, open_windows);
+
+ git_buf_dispose(&path);
+ git_revwalk_free(walk);
+ git_repository_free(repo);
+}
#include "clar_libgit2.h"
#include <git2.h>
-#include "fileops.h"
+#include "futils.h"
#include "hash.h"
#include "iterator.h"
#include "vector.h"
void test_pack_indexer__out_of_order(void)
{
git_indexer *idx = 0;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_indexer_append(
void test_pack_indexer__missing_trailer(void)
{
git_indexer *idx = 0;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_indexer_append(
void test_pack_indexer__leaky(void)
{
git_indexer *idx = 0;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_indexer_append(
void test_pack_indexer__fix_thin(void)
{
git_indexer *idx = NULL;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
git_repository *repo;
git_odb *odb;
git_oid id, should_id;
void test_pack_indexer__corrupt_length(void)
{
git_indexer *idx = NULL;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
git_repository *repo;
git_odb *odb;
git_oid id, should_id;
{
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
git_indexer *idx = 0;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
opts.verify = 1;
{
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
git_indexer *idx = 0;
- git_transfer_progress stats = { 0 };
+ git_indexer_progress stats = { 0 };
opts.verify = 1;
--- /dev/null
+#include "clar_libgit2.h"
+
+#include <git2.h>
+
+#include "midx.h"
+
+void test_pack_midx__parse(void)
+{
+ git_repository *repo;
+ struct git_midx_file *idx;
+ struct git_midx_entry e;
+ git_oid id;
+ git_buf midx_path = GIT_BUF_INIT;
+
+ cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
+ cl_git_pass(git_buf_joinpath(&midx_path, git_repository_path(repo), "objects/pack/multi-pack-index"));
+ cl_git_pass(git_midx_open(&idx, git_buf_cstr(&midx_path)));
+
+ cl_git_pass(git_oid_fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5"));
+ cl_git_pass(git_midx_entry_find(&e, idx, &id, GIT_OID_HEXSZ));
+ cl_assert_equal_oid(&e.sha1, &id);
+ cl_assert_equal_s(
+ (const char *)git_vector_get(&idx->packfile_names, e.pack_index),
+ "pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx");
+
+ git_midx_free(idx);
+ git_repository_free(repo);
+ git_buf_dispose(&midx_path);
+}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "pack.h"
#include "hash.h"
#include "iterator.h"
static git_indexer *_indexer;
static git_vector _commits;
static int _commits_is_initialized;
-static git_transfer_progress _stats;
+static git_indexer_progress _stats;
+
+extern bool git_disable_pack_keep_file_checks;
void test_pack_packbuilder__initialize(void)
{
unsigned int i;
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, false));
if (_commits_is_initialized) {
_commits_is_initialized = 0;
static int feed_indexer(void *ptr, size_t len, void *payload)
{
- git_transfer_progress *stats = (git_transfer_progress *)payload;
+ git_indexer_progress *stats = (git_indexer_progress *)payload;
return git_indexer_append(_indexer, ptr, len, stats);
}
void test_pack_packbuilder__create_pack(void)
{
- git_transfer_progress stats;
+ git_indexer_progress stats;
git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
git_hash_ctx ctx;
git_oid hash;
seed_packbuilder();
- git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL);
+ cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0, NULL, NULL));
git_oid_fmt(hex, git_packbuilder_hash(_packbuilder));
cl_assert_equal_s(hex, "7f5fa362c664d68ba7221259be1cbd187434b2f0");
}
+void test_pack_packbuilder__write_default_path(void)
+{
+ seed_packbuilder();
+
+ cl_git_pass(git_packbuilder_write(_packbuilder, NULL, 0, NULL, NULL));
+ cl_assert(git_path_exists("objects/pack/pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.idx"));
+ cl_assert(git_path_exists("objects/pack/pack-7f5fa362c664d68ba7221259be1cbd187434b2f0.pack"));
+}
+
static void test_write_pack_permission(mode_t given, mode_t expected)
{
struct stat statbuf;
seed_packbuilder();
- git_packbuilder_write(_packbuilder, ".", given, NULL, NULL);
+ cl_git_pass(git_packbuilder_write(_packbuilder, ".", given, NULL, NULL));
/* Windows does not return group/user bits from stat,
* files are never executable.
void test_pack_packbuilder__does_not_fsync_by_default(void)
{
seed_packbuilder();
- git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL);
+ cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL));
cl_assert_equal_sz(0, p_fsync__cnt);
}
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
p_fsync__cnt = 0;
seed_packbuilder();
- git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL);
+ cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL));
cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt);
}
cl_repo_set_bool(_repo, "core.fsyncObjectFiles", true);
p_fsync__cnt = 0;
seed_packbuilder();
- git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL);
+ cl_git_pass(git_packbuilder_write(_packbuilder, ".", 0666, NULL, NULL));
cl_assert_equal_sz(expected_fsyncs, p_fsync__cnt);
}
git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111);
git_indexer_free(idx);
}
+
+void test_pack_packbuilder__keep_file_check(void)
+{
+ assert(!git_disable_pack_keep_file_checks);
+ cl_git_pass(git_libgit2_opts(GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, true));
+ assert(git_disable_pack_keep_file_checks);
+}
cl_git_pass(git_object_lookup(&obj2, repo2, &id, GIT_OBJECT_ANY));
pos = 0;
- while ((error = git_strmap_next(&data, &pos, git__pack_cache)) == 0) {
+ while ((error = git_strmap_iterate(&data, git__pack_cache, &pos, NULL)) == 0) {
struct git_pack_file *pack = (struct git_pack_file *) data;
cl_assert_equal_i(2, pack->refcount.val);
}
- cl_assert_equal_i(3, git_strmap_num_entries(git__pack_cache));
+ cl_assert_equal_i(3, git_strmap_size(git__pack_cache));
git_object_free(obj1);
git_object_free(obj2);
git_repository_free(repo2);
/* we don't want to keep the packs open after the repos go away */
- cl_assert_equal_i(0, git_strmap_num_entries(git__pack_cache));
+ cl_assert_equal_i(0, git_strmap_size(git__pack_cache));
}
cl_assert_equal_i(0, delta->new_file.size);
}
+static void ensure_identical_patch_inout(const char *content) {
+ git_buf buf = GIT_BUF_INIT;
+ git_patch *patch;
+
+ cl_git_pass(git_patch_from_buffer(&patch, content, strlen(content), NULL));
+ cl_git_pass(git_patch_to_buf(&buf, patch));
+ cl_assert_equal_strn(git_buf_cstr(&buf), content, strlen(content));
+
+ git_patch_free(patch);
+ git_buf_dispose(&buf);
+}
+
void test_patch_parse__original_to_change_middle(void)
{
git_patch *patch;
strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
}
+void test_patch_parse__no_newline_at_end_of_new_file(void)
+{
+ ensure_identical_patch_inout(PATCH_APPEND_NO_NL);
+}
+
+void test_patch_parse__no_newline_at_end_of_old_file(void)
+{
+ ensure_identical_patch_inout(PATCH_APPEND_NO_NL_IN_OLD_FILE);
+}
+
void test_patch_parse__files_with_whitespaces_succeeds(void)
+{
+ ensure_identical_patch_inout(PATCH_NAME_WHITESPACE);
+}
+
+void test_patch_parse__lifetime_of_patch_does_not_depend_on_buffer(void)
+{
+ git_buf diff = GIT_BUF_INIT, rendered = GIT_BUF_INIT;
+ git_patch *patch;
+
+ cl_git_pass(git_buf_sets(&diff, PATCH_ORIGINAL_TO_CHANGE_MIDDLE));
+ cl_git_pass(git_patch_from_buffer(&patch, diff.ptr, diff.size, NULL));
+ git_buf_dispose(&diff);
+
+ cl_git_pass(git_patch_to_buf(&rendered, patch));
+ cl_assert_equal_s(PATCH_ORIGINAL_TO_CHANGE_MIDDLE, rendered.ptr);
+ git_buf_dispose(&rendered);
+
+ cl_git_pass(git_patch_to_buf(&rendered, patch));
+ cl_assert_equal_s(PATCH_ORIGINAL_TO_CHANGE_MIDDLE, rendered.ptr);
+ git_buf_dispose(&rendered);
+
+ git_patch_free(patch);
+}
+
+void test_patch_parse__binary_file_with_missing_paths(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_MISSING_PATHS,
+ strlen(PATCH_BINARY_FILE_WITH_MISSING_PATHS), NULL));
+}
+
+void test_patch_parse__binary_file_with_whitespace_paths(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS,
+ strlen(PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS), NULL));
+}
+
+void test_patch_parse__binary_file_with_empty_quoted_paths(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS,
+ strlen(PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS), NULL));
+}
+
+void test_patch_parse__binary_file_path_with_spaces(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_PATH_WITH_SPACES,
+ strlen(PATCH_BINARY_FILE_PATH_WITH_SPACES), NULL));
+}
+
+void test_patch_parse__binary_file_path_without_body_paths(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_PATH_WITHOUT_BODY_PATHS,
+ strlen(PATCH_BINARY_FILE_PATH_WITHOUT_BODY_PATHS), NULL));
+}
+
+void test_patch_parse__binary_file_with_truncated_delta(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_TRUNCATED_DELTA,
+ strlen(PATCH_BINARY_FILE_WITH_TRUNCATED_DELTA), NULL));
+ cl_assert_equal_s(git_error_last()->message, "truncated binary data at line 5");
+}
+
+void test_patch_parse__memory_leak_on_multiple_paths(void)
+{
+ git_patch *patch;
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_MULTIPLE_OLD_PATHS, strlen(PATCH_MULTIPLE_OLD_PATHS), NULL));
+}
+
+void test_patch_parse__truncated_no_newline_at_end_of_file(void)
+{
+ size_t len = strlen(PATCH_APPEND_NO_NL) - strlen("at end of file\n");
+ const git_diff_line *line;
+ git_patch *patch;
+
+ cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL, len, NULL));
+ cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 4));
+ cl_assert_equal_s(line->content, "\\ No newline ");
+
+ git_patch_free(patch);
+}
+
+void test_patch_parse__line_number_overflow(void)
{
git_patch *patch;
- cl_git_pass(git_patch_from_buffer(&patch, PATCH_NAME_WHITESPACE, strlen(PATCH_NAME_WHITESPACE), NULL));
+ cl_git_fail(git_patch_from_buffer(&patch, PATCH_INTMAX_NEW_LINES, strlen(PATCH_INTMAX_NEW_LINES), NULL));
git_patch_free(patch);
}
"-(this line is changed)\n" \
"+(THIS line is changed!)\n"
+/* A change in the middle and a deletion of the newline at the end of the file */
+
+#define FILE_CHANGE_MIDDLE_AND_LASTLINE \
+ "hey!\n" \
+ "this is some context!\n" \
+ "around some lines\n" \
+ "that will change\n" \
+ "yes it is!\n" \
+ "(THIS line is changed!)\n" \
+ "and this\n" \
+ "is additional context\n" \
+ "BELOW it! - (THIS line is changed!)"
+
+#define PATCH_ORIGINAL_TO_CHANGE_MIDDLE_AND_LASTLINE_NOCONTEXT \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..e05d36c 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -6 +6 @@ yes it is!\n" \
+ "-(this line is changed)\n" \
+ "+(THIS line is changed!)\n" \
+ "@@ -9 +9 @@ is additional context\n" \
+ "-below it!\n" \
+ "+BELOW it! - (THIS line is changed!)\n" \
+ "\\ No newline at end of file\n"
+
/* A deletion at the beginning of the file and a change in the middle */
#define FILE_DELETE_AND_CHANGE \
"@@ -9,0 +10 @@ below it!\n" \
"+insert at end\n"
+#define PATCH_DELETED_FILE_2_HUNKS \
+ "diff --git a/a b/a\n" \
+ "index 7f129fd..af431f2 100644\n" \
+ "--- a/a\n" \
+ "+++ b/a\n" \
+ "@@ -1 +1 @@\n" \
+ "-a contents 2\n" \
+ "+a contents\n" \
+ "diff --git a/c/d b/c/d\n" \
+ "deleted file mode 100644\n" \
+ "index 297efb8..0000000\n" \
+ "--- a/c/d\n" \
+ "+++ /dev/null\n" \
+ "@@ -1 +0,0 @@\n" \
+ "-c/d contents\n"
+
+#define PATCH_DELETED_FILE_2_HUNKS_SHUFFLED \
+ "diff --git a/c/d b/c/d\n" \
+ "deleted file mode 100644\n" \
+ "index 297efb8..0000000\n" \
+ "--- a/c/d\n" \
+ "+++ /dev/null\n" \
+ "@@ -1 +0,0 @@\n" \
+ "-c/d contents\n" \
+ "diff --git a/a b/a\n" \
+ "index 7f129fd..af431f2 100644\n" \
+ "--- a/a\n" \
+ "+++ b/a\n" \
+ "@@ -1 +1 @@\n" \
+ "-a contents 2\n" \
+ "+a contents\n"
+
#define PATCH_SIMPLE_COMMIT \
"commit 15e119375018fba121cf58e02a9f17fe22df0df8\n" \
"Author: Edward Thomson <ethomson@edwardthomson.com>\n" \
"rename from file.txt\n" \
"rename to newfile.txt\n"
+#define PATCH_RENAME_EXACT_WITH_MODE \
+ "diff --git a/RENAMED.md b/README.md\n" \
+ "old mode 100644\n" \
+ "new mode 100755\n" \
+ "similarity index 100%\n" \
+ "rename from RENAMED.md\n" \
+ "rename to README.md\n"
+
#define PATCH_RENAME_SIMILAR \
"diff --git a/file.txt b/newfile.txt\n" \
"similarity index 77%\n" \
"+added line with no nl\n" \
"\\ No newline at end of file\n"
+#define PATCH_APPEND_NO_NL_IN_OLD_FILE \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..83759c0 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -1,1 +1,1 @@\n" \
+ "-foo\n" \
+ "\\ No newline at end of file\n" \
+ "+foo\n"
+
#define PATCH_NAME_WHITESPACE \
"diff --git a/file with spaces.txt b/file with spaces.txt\n" \
"index 9432026..83759c0 100644\n" \
"index 27184d9..7c94f9e 100644\n" \
"Binary files a/binary.bin and b/binary.bin differ\n"
+#define PATCH_ADD_BINARY_NOT_PRINTED \
+ "diff --git a/test.bin b/test.bin\n" \
+ "new file mode 100644\n" \
+ "index 0000000..9e0f96a\n" \
+ "Binary files /dev/null and b/test.bin differ\n"
+
#define PATCH_ORIGINAL_NEW_FILE_WITH_SPACE \
"diff --git a/sp ace.txt b/sp ace.txt\n" \
"new file mode 100644\n" \
"+++ b/test-file\r\n" \
"@@ -0,0 +1 @@\r\n" \
"+a contents\r\n"
+
+#define PATCH_NO_EXTENDED_HEADERS \
+ "diff --git a/file b/file\n" \
+ "--- a/file\n" \
+ "+++ b/file\n" \
+ "@@ -1,3 +1,3 @@\n" \
+ " a\n" \
+ "-b\n" \
+ "+bb\n" \
+ " c\n"
+
+#define PATCH_BINARY_FILE_WITH_MISSING_PATHS \
+ "diff --git \n" \
+ "--- \n" \
+ "+++ \n" \
+ "Binary files "
+
+#define PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS \
+ "diff --git a/file b/file\n" \
+ "--- \n" \
+ "+++ \n" \
+ "Binary files "
+
+#define PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS \
+ "diff --git a/file b/file\n" \
+ "--- \"\"\n" \
+ "+++ \"\"\n" \
+ "Binary files "
+
+#define PATCH_BINARY_FILE_PATH_WITH_SPACES \
+ "diff --git a b c d e f\n" \
+ "--- a b c\n" \
+ "+++ d e f\n" \
+ "Binary files a b c and d e f differ"
+
+#define PATCH_BINARY_FILE_PATH_WITHOUT_BODY_PATHS \
+ "diff --git a b c d e f\n" \
+ "--- \n" \
+ "+++ \n" \
+ "Binary files a b c and d e f differ"
+
+#define PATCH_BINARY_FILE_WITH_TRUNCATED_DELTA \
+ "diff --git a/file b/file\n" \
+ "index 1420..b71f\n" \
+ "GIT binary patch\n" \
+ "delta 7\n" \
+ "d"
+
+#define PATCH_MULTIPLE_OLD_PATHS \
+ "diff --git \n" \
+ "--- \n" \
+ "+++ \n" \
+ "index 0000..7DDb\n" \
+ "--- \n"
+
+#define PATCH_INTMAX_NEW_LINES \
+ "diff --git a/file b/file\n" \
+ "--- a/file\n" \
+ "+++ b/file\n" \
+ "@@ -0 +2147483647 @@\n" \
+ "\n" \
+ " "
strlen(PATCH_RENAME_EXACT));
}
+void test_patch_print__rename_exact_with_mode(void)
+{
+ patch_print_from_patchfile(PATCH_RENAME_EXACT_WITH_MODE,
+ strlen(PATCH_RENAME_EXACT_WITH_MODE));
+}
+
void test_patch_print__rename_similar(void)
{
patch_print_from_patchfile(PATCH_RENAME_SIMILAR,
patch_print_from_patchfile(PATCH_BINARY_NOT_PRINTED,
strlen(PATCH_BINARY_NOT_PRINTED));
}
+
+void test_patch_print__binary_add_not_shown(void)
+{
+ patch_print_from_patchfile(PATCH_ADD_BINARY_NOT_PRINTED,
+ strlen(PATCH_ADD_BINARY_NOT_PRINTED));
+}
test_join_unrooted("c:/foo", 2, "c:/foo", "c:/asdf");
test_join_unrooted("c:/foo/bar", 2, "c:/foo/bar", "c:/asdf");
+#ifdef GIT_WIN32
+ /* Paths starting with '\\' are absolute */
+ test_join_unrooted("\\bar", 0, "\\bar", "c:/foo/");
+ test_join_unrooted("\\\\network\\bar", 9, "\\\\network\\bar", "c:/foo/");
+#else
+ /* Paths starting with '\\' are not absolute on non-Windows systems */
+ test_join_unrooted("/foo/\\bar", 4, "\\bar", "/foo");
+ test_join_unrooted("c:/foo/\\bar", 7, "\\bar", "c:/foo/");
+#endif
+
/* Base is returned when it's provided and is the prefix */
test_join_unrooted("c:/foo/bar/foobar", 6, "c:/foo/bar/foobar", "c:/foo");
test_join_unrooted("c:/foo/bar/foobar", 10, "c:/foo/bar/foobar", "c:/foo/bar");
#endif
}
+void test_utf8_to_utf16_relative(const char* utf8_in, const wchar_t* utf16_expected)
+{
+#ifdef GIT_WIN32
+ git_win32_path path_utf16;
+ int path_utf16len;
+
+ cl_assert((path_utf16len = git_win32_path_relative_from_utf8(path_utf16, utf8_in)) >= 0);
+ cl_assert_equal_wcs(utf16_expected, path_utf16);
+ cl_assert_equal_i(wcslen(utf16_expected), path_utf16len);
+#else
+ GIT_UNUSED(utf8_in);
+ GIT_UNUSED(utf16_expected);
+#endif
+}
+
void test_path_win32__utf8_to_utf16(void)
{
#ifdef GIT_WIN32
#endif
}
+void test_path_win32__keeps_relative(void)
+{
+#ifdef GIT_WIN32
+ /* Relative paths stay relative */
+ test_utf8_to_utf16_relative("Foo", L"Foo");
+ test_utf8_to_utf16_relative("..\\..\\Foo", L"..\\..\\Foo");
+ test_utf8_to_utf16_relative("Foo\\..", L"Foo\\..");
+ test_utf8_to_utf16_relative("Foo\\..\\..", L"Foo\\..\\..");
+ test_utf8_to_utf16_relative("Foo\\Bar", L"Foo\\Bar");
+ test_utf8_to_utf16_relative("Foo\\..\\Bar", L"Foo\\..\\Bar");
+ test_utf8_to_utf16_relative("../../Foo", L"..\\..\\Foo");
+ test_utf8_to_utf16_relative("Foo/..", L"Foo\\..");
+ test_utf8_to_utf16_relative("Foo/../..", L"Foo\\..\\..");
+ test_utf8_to_utf16_relative("Foo/Bar", L"Foo\\Bar");
+ test_utf8_to_utf16_relative("Foo/../Bar", L"Foo\\..\\Bar");
+ test_utf8_to_utf16_relative("Foo/../Bar/", L"Foo\\..\\Bar\\");
+ test_utf8_to_utf16_relative("", L"");
+
+ /* Absolute paths are canonicalized */
+ test_utf8_to_utf16_relative("\\Foo", L"\\\\?\\C:\\Foo");
+ test_utf8_to_utf16_relative("/Foo/Bar/", L"\\\\?\\C:\\Foo\\Bar");
+ test_utf8_to_utf16_relative("\\\\server\\c$\\unc\\path", L"\\\\?\\UNC\\server\\c$\\unc\\path");
+#endif
+}
+
#ifdef GIT_WIN32
static void test_canonicalize(const wchar_t *in, const wchar_t *expected)
{
test_canonicalize(L"C:/Foo/Bar", L"C:\\Foo\\Bar");
test_canonicalize(L"C:/", L"C:\\");
- test_canonicalize(L"Foo\\\\Bar\\\\Asdf\\\\", L"Foo\\Bar\\Asdf");
- test_canonicalize(L"Foo\\\\Bar\\\\..\\\\Asdf\\", L"Foo\\Asdf");
- test_canonicalize(L"Foo\\\\Bar\\\\.\\\\Asdf\\", L"Foo\\Bar\\Asdf");
- test_canonicalize(L"Foo\\\\..\\Bar\\\\.\\\\Asdf\\", L"Bar\\Asdf");
- test_canonicalize(L"\\", L"");
- test_canonicalize(L"", L"");
- test_canonicalize(L"Foo\\..\\..\\..\\..", L"");
- test_canonicalize(L"..\\..\\..\\..", L"");
- test_canonicalize(L"\\..\\..\\..\\..", L"");
-
test_canonicalize(L"\\\\?\\C:\\Foo\\Bar", L"\\\\?\\C:\\Foo\\Bar");
test_canonicalize(L"\\\\?\\C:\\Foo\\Bar\\", L"\\\\?\\C:\\Foo\\Bar");
test_canonicalize(L"\\\\?\\C:\\\\Foo\\.\\Bar\\\\..\\", L"\\\\?\\C:\\Foo");
git_status_list *status_list;
const git_status_entry *status_entry;
git_oid pick_id, file1_id;
+ git_oid master_id, beef_id;
+
+ git_oid_fromstr(&master_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00");
+ git_oid_fromstr(&beef_id, "b146bd7608eac53d9bf9e1a6963543588b555c64");
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL));
+ cl_assert_equal_s("refs/heads/beef", git_rebase_orig_head_name(rebase));
+ cl_assert_equal_oid(&beef_id, git_rebase_orig_head_id(rebase));
+
+ cl_assert_equal_s("master", git_rebase_onto_name(rebase));
+ cl_assert_equal_oid(&master_id, git_rebase_onto_id(rebase));
+
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
git_oid_fromstr(&pick_id, "da9c51a23d02d931a486f45ad18cda05cf5d2b94");
--- /dev/null
+#include "clar_libgit2.h"
+#include "git2/rebase.h"
+
+static git_repository *repo;
+static git_signature *signature;
+
+/* Fixture setup and teardown */
+void test_rebase_sign__initialize(void)
+{
+ repo = cl_git_sandbox_init("rebase");
+ cl_git_pass(git_signature_new(&signature, "Rebaser",
+ "rebaser@rebaser.rb", 1405694510, 0));
+}
+
+void test_rebase_sign__cleanup(void)
+{
+ git_signature_free(signature);
+ cl_git_sandbox_cleanup();
+}
+
+static const char *expected_commit_content = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+parent f87d14a4a236582a0278a916340a793714256864\n\
+author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
+committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
+\n\
+Modification 3 to gravy\n";
+
+int signing_cb_passthrough(
+ git_buf *signature,
+ git_buf *signature_field,
+ const char *commit_content,
+ void *payload)
+{
+ cl_assert_equal_b(false, git_buf_is_allocated(signature));
+ cl_assert_equal_b(false, git_buf_is_allocated(signature_field));
+ cl_assert_equal_s(expected_commit_content, commit_content);
+ cl_assert_equal_p(NULL, payload);
+ return GIT_PASSTHROUGH;
+}
+
+/* git checkout gravy ; git rebase --merge veal */
+void test_rebase_sign__passthrough_signing_cb(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_operation *rebase_operation;
+ git_oid commit_id, expected_id;
+ git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
+ git_commit *commit;
+ const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+parent f87d14a4a236582a0278a916340a793714256864\n\
+author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
+committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n";
+
+ rebase_opts.signing_cb = signing_cb_passthrough;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_opts));
+
+ cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+ git_oid_fromstr(&expected_id, "129183968a65abd6c52da35bff43325001bfc630");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
+ cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
+ cl_assert_equal_s(expected_commit_raw_header, git_commit_raw_header(commit));
+
+ cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase));
+
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_commit_free(commit);
+ git_rebase_free(rebase);
+}
+
+int signing_cb_gpg(
+ git_buf *signature,
+ git_buf *signature_field,
+ const char *commit_content,
+ void *payload)
+{
+ const char *gpg_signature = "-----BEGIN PGP SIGNATURE-----\n\
+\n\
+iQIzBAEBCgAdFiEEgVlDEfSlmKn0fvGgK++h5T2/ctIFAlwZcrAACgkQK++h5T2/\n\
+ctIPVhAA42RyZhMdKl5Bm0KtQco2scsukIg2y7tjSwhti91zDu3HQgpusjjo0fQx\n\
+ZzB+OrmlvQ9CDcGpZ0THIzXD8GRJoDMPqdrvZVrBWkGcHvw7/YPA8skzsjkauJ8W\n\
+7lzF5LCuHSS6OUmPT/+5hEHPin5PB3zhfszyC+Q7aujnIuPJMrKiMnUa+w1HWifM\n\
+km49OOygQ9S6NQoVuEQede22+c76DlDL7yFghGoo1f0sKCE/9LW6SEnwI/bWv9eo\n\
+nom5vOPrvQeJiYCQk+2DyWo8RdSxINtY+G9bPE4RXm+6ZgcXECPm9TYDIWpL36fC\n\
+jvtGLs98woWFElOziBMp5Tb630GMcSI+q5ivHfJ3WS5NKLYLHBNK4iSFN0/dgAnB\n\
+dj6GcKXKWnIBWn6ZM4o40pcM5KSRUUCLtA0ZmjJH4c4zx3X5fUxd+enwkf3e9VZO\n\
+fNKC/+xfq6NfoPUPK9+UnchHpJaJw7RG5tZS+sWCz2xpQ1y3/o49xImNyM3wnpvB\n\
+cRAZabqIHpZa9/DIUkELOtCzln6niqkjRgg3M/YCCNznwV+0RNgz87VtyTPerdef\n\
+xrqn0+ROMF6ebVqIs6PPtuPkxnAJu7TMKXVB5rFnAewS24e6cIGFzeIA7810py3l\n\
+cttVRsdOoego+fiy08eFE+aJIeYiINRGhqOBTsuqG4jIdpdKxPE=\n\
+=KbsY\n\
+-----END PGP SIGNATURE-----";
+
+ cl_assert_equal_b(false, git_buf_is_allocated(signature));
+ cl_assert_equal_b(false, git_buf_is_allocated(signature_field));
+ cl_assert_equal_s(expected_commit_content, commit_content);
+ cl_assert_equal_p(NULL, payload);
+
+ cl_git_pass(git_buf_set(signature, gpg_signature, strlen(gpg_signature) + 1));
+ return GIT_OK;
+}
+
+/* git checkout gravy ; git rebase --merge veal */
+void test_rebase_sign__gpg_with_no_field(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_operation *rebase_operation;
+ git_oid commit_id, expected_id;
+ git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
+ git_commit *commit;
+ const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+parent f87d14a4a236582a0278a916340a793714256864\n\
+author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
+committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
+gpgsig -----BEGIN PGP SIGNATURE-----\n\
+ \n\
+ iQIzBAEBCgAdFiEEgVlDEfSlmKn0fvGgK++h5T2/ctIFAlwZcrAACgkQK++h5T2/\n\
+ ctIPVhAA42RyZhMdKl5Bm0KtQco2scsukIg2y7tjSwhti91zDu3HQgpusjjo0fQx\n\
+ ZzB+OrmlvQ9CDcGpZ0THIzXD8GRJoDMPqdrvZVrBWkGcHvw7/YPA8skzsjkauJ8W\n\
+ 7lzF5LCuHSS6OUmPT/+5hEHPin5PB3zhfszyC+Q7aujnIuPJMrKiMnUa+w1HWifM\n\
+ km49OOygQ9S6NQoVuEQede22+c76DlDL7yFghGoo1f0sKCE/9LW6SEnwI/bWv9eo\n\
+ nom5vOPrvQeJiYCQk+2DyWo8RdSxINtY+G9bPE4RXm+6ZgcXECPm9TYDIWpL36fC\n\
+ jvtGLs98woWFElOziBMp5Tb630GMcSI+q5ivHfJ3WS5NKLYLHBNK4iSFN0/dgAnB\n\
+ dj6GcKXKWnIBWn6ZM4o40pcM5KSRUUCLtA0ZmjJH4c4zx3X5fUxd+enwkf3e9VZO\n\
+ fNKC/+xfq6NfoPUPK9+UnchHpJaJw7RG5tZS+sWCz2xpQ1y3/o49xImNyM3wnpvB\n\
+ cRAZabqIHpZa9/DIUkELOtCzln6niqkjRgg3M/YCCNznwV+0RNgz87VtyTPerdef\n\
+ xrqn0+ROMF6ebVqIs6PPtuPkxnAJu7TMKXVB5rFnAewS24e6cIGFzeIA7810py3l\n\
+ cttVRsdOoego+fiy08eFE+aJIeYiINRGhqOBTsuqG4jIdpdKxPE=\n\
+ =KbsY\n\
+ -----END PGP SIGNATURE-----\n";
+
+ rebase_opts.signing_cb = signing_cb_gpg;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_opts));
+
+ cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+ git_oid_fromstr(&expected_id, "bf78348e45c8286f52b760f1db15cb6da030f2ef");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
+ cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
+ cl_assert_equal_s(expected_commit_raw_header, git_commit_raw_header(commit));
+
+ cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase));
+
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_commit_free(commit);
+ git_rebase_free(rebase);
+}
+
+
+int signing_cb_magic_field(
+ git_buf *signature,
+ git_buf *signature_field,
+ const char *commit_content,
+ void *payload)
+{
+ const char *signature_content = "magic word: pretty please";
+ const char *signature_field_content = "magicsig";
+
+ cl_assert_equal_b(false, git_buf_is_allocated(signature));
+ cl_assert_equal_b(false, git_buf_is_allocated(signature_field));
+ cl_assert_equal_s(expected_commit_content, commit_content);
+ cl_assert_equal_p(NULL, payload);
+
+ cl_git_pass(git_buf_set(signature, signature_content,
+ strlen(signature_content) + 1));
+ cl_git_pass(git_buf_set(signature_field, signature_field_content,
+ strlen(signature_field_content) + 1));
+
+ return GIT_OK;
+}
+
+/* git checkout gravy ; git rebase --merge veal */
+void test_rebase_sign__custom_signature_field(void)
+{
+ git_rebase *rebase;
+ git_reference *branch_ref, *upstream_ref;
+ git_annotated_commit *branch_head, *upstream_head;
+ git_rebase_operation *rebase_operation;
+ git_oid commit_id, expected_id;
+ git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
+ git_commit *commit;
+ const char *expected_commit_raw_header = "tree cd99b26250099fc38d30bfaed7797a7275ed3366\n\
+parent f87d14a4a236582a0278a916340a793714256864\n\
+author Edward Thomson <ethomson@edwardthomson.com> 1405625055 -0400\n\
+committer Rebaser <rebaser@rebaser.rb> 1405694510 +0000\n\
+magicsig magic word: pretty please\n";
+
+ rebase_opts.signing_cb = signing_cb_magic_field;
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal"));
+
+ cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_opts));
+
+ cl_git_pass(git_rebase_next(&rebase_operation, rebase));
+ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
+
+ git_oid_fromstr(&expected_id, "f46a4a8d26ae411b02aa61b7d69576627f4a1e1c");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
+ cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
+ cl_assert_equal_s(expected_commit_raw_header, git_commit_raw_header(commit));
+
+ cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase));
+
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+ git_annotated_commit_free(branch_head);
+ git_annotated_commit_free(upstream_head);
+ git_commit_free(commit);
+ git_rebase_free(rebase);
+}
--- /dev/null
+#include "clar_libgit2.h"
+
+#include "futils.h"
+#include "refs.h"
+#include "ref_helpers.h"
+
+static git_repository *g_repo;
+
+static const char *loose_tag_ref_name = "refs/tags/e90810b";
+
+void test_refs_basic__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("testrepo");
+ cl_git_pass(git_repository_set_ident(g_repo, "me", "foo@example.com"));
+}
+
+void test_refs_basic__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_refs_basic__reference_realloc(void)
+{
+ git_reference *ref;
+ git_reference *new_ref;
+ const char *new_name = "refs/tags/awful/name-which-is/clearly/really-that-much/longer-than/the-old-one";
+
+ /* Retrieval of the reference to rename */
+ cl_git_pass(git_reference_lookup(&ref, g_repo, loose_tag_ref_name));
+
+ new_ref = git_reference__realloc(&ref, new_name);
+ cl_assert(new_ref != NULL);
+ git_reference_free(new_ref);
+ git_reference_free(ref);
+
+ /* Reload, so we restore the value */
+ cl_git_pass(git_reference_lookup(&ref, g_repo, loose_tag_ref_name));
+
+ cl_git_pass(git_reference_rename(&new_ref, ref, new_name, 1, "log message"));
+ cl_assert(ref != NULL);
+ cl_assert(new_ref != NULL);
+ git_reference_free(new_ref);
+ git_reference_free(ref);
+}
--- /dev/null
+#include "clar_libgit2.h"
+#include "refs.h"
+#include "worktree/worktree_helpers.h"
+
+static git_repository *repo;
+
+static void assert_checked_out(git_repository *repo, const char *branch, int checked_out)
+{
+ git_reference *ref;
+
+ cl_git_pass(git_reference_lookup(&ref, repo, branch));
+ cl_assert(git_branch_is_checked_out(ref) == checked_out);
+
+ git_reference_free(ref);
+}
+
+void test_refs_branches_checkedout__simple_repo(void)
+{
+ repo = cl_git_sandbox_init("testrepo");
+ assert_checked_out(repo, "refs/heads/master", 1);
+ assert_checked_out(repo, "refs/heads/executable", 0);
+ cl_git_sandbox_cleanup();
+}
+
+void test_refs_branches_checkedout__worktree(void)
+{
+ static worktree_fixture fixture =
+ WORKTREE_FIXTURE_INIT("testrepo", "testrepo-worktree");
+
+ setup_fixture_worktree(&fixture);
+
+ assert_checked_out(fixture.repo, "refs/heads/master", 1);
+ assert_checked_out(fixture.repo, "refs/heads/testrepo-worktree", 1);
+
+ assert_checked_out(fixture.worktree, "refs/heads/master", 1);
+ assert_checked_out(fixture.worktree, "refs/heads/testrepo-worktree", 1);
+
+ cleanup_fixture_worktree(&fixture);
+}
+
+void test_refs_branches_checkedout__head_is_not_checked_out(void)
+{
+ repo = cl_git_sandbox_init("testrepo");
+ assert_checked_out(repo, "HEAD", 0);
+ cl_git_sandbox_cleanup();
+}
+
+void test_refs_branches_checkedout__master_in_bare_repo_is_not_checked_out(void)
+{
+ repo = cl_git_sandbox_init("testrepo.git");
+ assert_checked_out(repo, "refs/heads/master", 0);
+ cl_git_sandbox_cleanup();
+}
#include "refs.h"
#include "repo/repo_helpers.h"
#include "config/config_helpers.h"
-#include "fileops.h"
+#include "futils.h"
#include "reflog.h"
static git_repository *repo;
repo = NULL;
}
-void test_refs_branches_lookup__can_retrieve_a_local_branch(void)
+void test_refs_branches_lookup__can_retrieve_a_local_branch_local(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
}
-void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch(void)
+void test_refs_branches_lookup__can_retrieve_a_local_branch_all(void)
+{
+ cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_ALL));
+}
+
+void test_refs_branches_lookup__trying_to_retrieve_a_local_branch_remote(void)
+{
+ cl_git_fail(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_REMOTE));
+}
+
+void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch_remote(void)
{
cl_git_pass(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_REMOTE));
}
+void test_refs_branches_lookup__can_retrieve_a_remote_tracking_branch_all(void)
+{
+ cl_git_pass(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_ALL));
+}
+
+void test_refs_branches_lookup__trying_to_retrieve_a_remote_tracking_branch_local(void)
+{
+ cl_git_fail(git_branch_lookup(&branch, repo, "test/master", GIT_BRANCH_LOCAL));
+}
+
void test_refs_branches_lookup__trying_to_retrieve_an_unknown_branch_returns_ENOTFOUND(void)
{
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "where/are/you", GIT_BRANCH_LOCAL));
cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "over/here", GIT_BRANCH_REMOTE));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_branch_lookup(&branch, repo, "maybe/here", GIT_BRANCH_ALL));
}
void test_refs_branches_lookup__trying_to_retrieve_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
git_branch_lookup(&branch, repo, "are/you/inv@{id", GIT_BRANCH_LOCAL));
cl_assert_equal_i(GIT_EINVALIDSPEC,
git_branch_lookup(&branch, repo, "yes/i am", GIT_BRANCH_REMOTE));
+ cl_assert_equal_i(GIT_EINVALIDSPEC,
+ git_branch_lookup(&branch, repo, "inv al/id", GIT_BRANCH_ALL));
}
void test_refs_create__propagate_eexists(void)
{
- int error;
git_oid oid;
- git_reference *ref;
/* Make sure it works for oid and for symbolic both */
- git_oid_fromstr(&oid, current_master_tip);
- error = git_reference_create(&ref, g_repo, current_head_target, &oid, false, NULL);
- cl_assert(error == GIT_EEXISTS);
-
- error = git_reference_symbolic_create(&ref, g_repo, "HEAD", current_head_target, false, NULL);
- cl_assert(error == GIT_EEXISTS);
+ cl_git_pass(git_oid_fromstr(&oid, current_master_tip));
+ cl_git_fail_with(GIT_EEXISTS, git_reference_create(NULL, g_repo, current_head_target, &oid, false, NULL));
+ cl_git_fail_with(GIT_EEXISTS, git_reference_symbolic_create(NULL, g_repo, "HEAD", current_head_target, false, NULL));
}
void test_refs_create__existing_dir_propagates_edirectory(void)
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/reflog.h"
#include "git2/refdb.h"
#include "reflog.h"
cl_git_fail(git_reference_lookup(&ref, g_repo, packed_test_head_name));
}
+
+void test_refs_delete__head(void)
+{
+ git_reference *ref;
+
+ /* Check that it is not possible to delete HEAD */
+
+ cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
+ cl_git_fail(git_reference_delete(ref));
+ git_reference_free(ref);
+}
void test_refs_foreachglob__retrieve_all_refs(void)
{
- /* 12 heads (including one packed head) + 1 note + 2 remotes + 7 tags */
- assert_retrieval("*", 22);
+ /* 12 heads (including one packed head) + 1 note + 2 remotes + 7 tags + 1 blob */
+ assert_retrieval("*", 23);
}
void test_refs_foreachglob__retrieve_remote_branches(void)
}
static const char *refnames[] = {
+ "refs/blobs/annotated_tag_to_blob",
"refs/heads/br2",
"refs/heads/cannot-fetch",
"refs/heads/chomped",
};
static const char *refnames_with_symlink[] = {
+ "refs/blobs/annotated_tag_to_blob",
"refs/heads/br2",
"refs/heads/cannot-fetch",
"refs/heads/chomped",
git_vector output;
git_reference *ref;
- cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
+ cl_git_pass(git_vector_init(&output, 33, &refcmp_cb));
cl_git_pass(git_reference_iterator_new(&iter, repo));
while (1) {
void test_refs_iterator__foreach(void)
{
git_vector output;
- cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
+ cl_git_pass(git_vector_init(&output, 33, &refcmp_cb));
cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
assert_all_refnames_match(refnames, &output);
}
/* We have exactly 12 refs in total if we include the packed ones:
* there is a reference that exists both in the packfile and as
* loose, but we only list it once */
- cl_assert_equal_i((int)ref_list.count, 18);
+ cl_assert_equal_i((int)ref_list.count, 19);
- git_strarray_free(&ref_list);
+ git_strarray_dispose(&ref_list);
}
void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_extension(void)
"144344043ba4d4a405da03de3844aa829ae8be0e\n");
cl_git_pass(git_reference_list(&ref_list, g_repo));
- cl_assert_equal_i((int)ref_list.count, 18);
+ cl_assert_equal_i((int)ref_list.count, 19);
- git_strarray_free(&ref_list);
+ git_strarray_dispose(&ref_list);
}
for (i = 0; i < ref_list.count; i++)
cl_assert(git__prefixcmp(ref_list.strings[i], "/") != 0);
- git_strarray_free(&ref_list);
+ git_strarray_dispose(&ref_list);
git_repository_free(repo);
}
cl_assert(ref_list.count > 0);
- git_strarray_free(&ref_list);
+ git_strarray_dispose(&ref_list);
git_repository_free(repo);
}
cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i(0, ref_list.count);
- git_strarray_free(&ref_list);
+ git_strarray_dispose(&ref_list);
}
void test_refs_normalize__refspec_pattern(void)
{
- ensure_refname_invalid(
- GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar");
- ensure_refname_invalid(
- GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar");
- ensure_refname_invalid(
- GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar");
+ ensure_refname_normalized(
+ GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar", "heads/*foo/bar");
+ ensure_refname_normalized(
+ GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar", "heads/foo*/bar");
+ ensure_refname_normalized(
+ GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar", "heads/f*o/bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo");
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/reflog.h"
#include "git2/refdb.h"
#include "reflog.h"
git_reference_free(ref);
/* We cannot delete a symbolic value that doesn't match */
- cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
- cl_git_pass(git_reference_symbolic_create_matching(&ref2, g_repo, "HEAD", other_refname, 1, NULL, refname));
+ cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/symref"));
+ cl_git_pass(git_reference_symbolic_create_matching(&ref2, g_repo, "refs/symref", other_refname, 1, NULL, refname));
cl_git_fail_with(GIT_EMODIFIED, git_reference_delete(ref));
git_reference_free(ref);
git_oid_fromstr(&other_id, other_commit_id);
/* Removing a symbolic ref when it's currently direct should fail */
- cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
- cl_git_pass(git_reference_create(&ref2, g_repo, "HEAD", &id, 1, NULL));
+ cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/symref"));
+ cl_git_pass(git_reference_create(&ref2, g_repo, "refs/symref", &id, 1, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_delete(ref));
git_reference_free(ref);
git_reference_free(ref2);
- cl_git_pass(git_reference_symbolic_create(&ref, g_repo, "HEAD", refname, 1, NULL));
+ cl_git_pass(git_reference_symbolic_create(&ref, g_repo, "refs/symref", refname, 1, NULL));
git_reference_free(ref);
/* Updating a symbolic ref when it's currently direct should fail */
- cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD"));
- cl_git_pass(git_reference_create(&ref2, g_repo, "HEAD", &id, 1, NULL));
+ cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/symref"));
+ cl_git_pass(git_reference_create(&ref2, g_repo, "refs/symref", &id, 1, NULL));
cl_git_fail_with(GIT_EMODIFIED, git_reference_symbolic_set_target(&ref3, ref, other_refname, NULL));
git_reference_free(ref);
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "refs.h"
void test_refs_reflog_messages__setting_head_updates_reflog(void)
{
git_object *tag;
- git_signature *sig;
git_annotated_commit *annotated;
- cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
-
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); /* 4 */
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/unborn"));
cl_git_pass(git_revparse_single(&tag, g_repo, "tags/test"));
git_annotated_commit_free(annotated);
git_object_free(tag);
- git_signature_free(sig);
}
void test_refs_reflog_messages__setting_head_to_same_target_ignores_reflog(void)
void test_refs_reflog_messages__detaching_writes_reflog(void)
{
- git_signature *sig;
git_oid id;
const char *msg;
- cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
-
msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d";
git_oid_fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d");
cl_git_pass(git_repository_set_head_detached(g_repo, &id));
"e90810b8df3e80c413d903f631643c716887138d",
"258f0e2a959a364e40ed6603d5d44fbb24765b10",
NULL, msg);
-
- git_signature_free(sig);
}
void test_refs_reflog_messages__orphan_branch_does_not_count(void)
git_reference_free(reference);
}
+void test_refs_reflog_messages__newline_gets_replaced(void)
+{
+ const git_reflog_entry *entry;
+ git_signature *signature;
+ git_reflog *reflog;
+ git_oid oid;
+
+ cl_git_pass(git_signature_now(&signature, "me", "foo@example.com"));
+ cl_git_pass(git_oid_fromstr(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
+
+ cl_git_pass(git_reflog_read(&reflog, g_repo, "HEAD"));
+ cl_assert_equal_sz(7, git_reflog_entrycount(reflog));
+ cl_git_pass(git_reflog_append(reflog, &oid, signature, "inner\nnewline"));
+ cl_assert_equal_sz(8, git_reflog_entrycount(reflog));
+
+ cl_assert(entry = git_reflog_entry_byindex(reflog, 0));
+ cl_assert_equal_s(git_reflog_entry_message(entry), "inner newline");
+
+ git_signature_free(signature);
+ git_reflog_free(reflog);
+}
void test_refs_reflog_messages__renaming_ref(void)
{
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/reflog.h"
#include "reflog.h"
cl_git_pass(git_signature_now(&committer, "foo", "foo@bar"));
cl_git_pass(git_reflog_read(&reflog, g_repo, new_ref));
-
- cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline"));
cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL));
cl_git_pass(git_reflog_append(reflog, &oid, committer, commit_msg "\n"));
cl_git_pass(git_reflog_write(reflog));
- git_reflog_free(reflog);
assert_appends(committer, &oid);
+ git_reflog_free(reflog);
git_signature_free(committer);
}
git_buf_dispose(&subtrees_log_path);
}
-void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_returns_error(void)
+void test_refs_reflog_reflog__reading_a_reflog_with_invalid_format_succeeds(void)
{
git_reflog *reflog;
- const git_error *error;
const char *refname = "refs/heads/newline";
const char *refmessage =
"Reflog*message with a newline and enough content after it to pass the GIT_REFLOG_SIZE_MIN check inside reflog_parse.";
+ const git_reflog_entry *entry;
git_reference *ref;
git_oid id;
git_buf logpath = GIT_BUF_INIT, logcontents = GIT_BUF_INIT;
char *star;
- git_oid_fromstr(&id, current_master_tip);
-
- /* create a new branch */
+ /* Create a new branch. */
+ cl_git_pass(git_oid_fromstr(&id, current_master_tip));
cl_git_pass(git_reference_create(&ref, g_repo, refname, &id, 1, refmessage));
- /* corrupt the branch reflog by introducing a newline inside the reflog message (we replace '*' with '\n') */
- git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname);
+ /*
+ * Corrupt the branch reflog by introducing a newline inside the reflog message.
+ * We do this by replacing '*' with '\n'
+ */
+ cl_git_pass(git_buf_join_n(&logpath, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname));
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
cl_assert((star = strchr(git_buf_cstr(&logcontents), '*')) != NULL);
*star = '\n';
cl_git_rewritefile(git_buf_cstr(&logpath), git_buf_cstr(&logcontents));
- /* confirm that the file was rewritten successfully and now contains a '\n' in the expected location */
+ /*
+ * Confirm that the file was rewritten successfully
+ * and now contains a '\n' in the expected location
+ */
cl_git_pass(git_futils_readbuffer(&logcontents, git_buf_cstr(&logpath)));
cl_assert(strstr(git_buf_cstr(&logcontents), "Reflog\nmessage") != NULL);
- /* clear the error state so we can capture the error generated by git_reflog_read */
- git_error_clear();
-
- cl_git_fail(git_reflog_read(&reflog, g_repo, refname));
-
- error = git_error_last();
-
- cl_assert(error != NULL);
- cl_assert_equal_s("unable to parse OID - contains invalid characters", error->message);
+ cl_git_pass(git_reflog_read(&reflog, g_repo, refname));
+ cl_assert(entry = git_reflog_entry_byindex(reflog, 0));
+ cl_assert_equal_s(git_reflog_entry_message(entry), "Reflog");
git_reference_free(ref);
+ git_reflog_free(reflog);
git_buf_dispose(&logpath);
git_buf_dispose(&logcontents);
}
void cl_reflog_check_entry_(git_repository *repo, const char *reflog, size_t idx,
const char *old_spec, const char *new_spec,
- const char *email, const char *message, const char *file, int line)
+ const char *email, const char *message,
+ const char *file, const char *func, int line)
{
git_reflog *log;
const git_reflog_entry *entry;
cl_git_pass(git_reflog_read(&log, repo, reflog));
entry = git_reflog_entry_byindex(log, idx);
if (entry == NULL)
- clar__fail(file, line, "Reflog has no such entry", NULL, 1);
+ clar__fail(file, func, line, "Reflog has no such entry", NULL, 1);
if (old_spec) {
git_object *obj = NULL;
git_buf_printf(&result, "\tMessage: \"%s\" != \"%s\"\n", message, entry_msg);
}
if (git_buf_len(&result) != 0)
- clar__fail(file, line, "Reflog entry mismatch", git_buf_cstr(&result), 1);
+ clar__fail(file, func, line, "Reflog entry mismatch", git_buf_cstr(&result), 1);
git_buf_dispose(&result);
git_reflog_free(log);
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/reflog.h"
#include "reflog.h"
#include "refs.h"
cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/foo", &id, NULL, NULL));
cl_git_pass(git_transaction_commit(g_tx));
}
+
+void test_refs_transactions__error_on_locking_locked_ref(void)
+{
+ git_oid id;
+ git_transaction *g_tx_with_lock;
+ git_repository *g_repo_with_locking_tx;
+ const char *g_repo_path = git_repository_path(g_repo);
+
+ /* prepare a separate transaction in another instance of testrepo and lock master */
+ cl_git_pass(git_repository_open(&g_repo_with_locking_tx, g_repo_path));
+ cl_git_pass(git_transaction_new(&g_tx_with_lock, g_repo_with_locking_tx));
+ cl_git_pass(git_transaction_lock_ref(g_tx_with_lock, "refs/heads/master"));
+
+ /* lock reference for set_target */
+ cl_git_pass(git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"));
+ cl_git_fail_with(GIT_ELOCKED, git_transaction_lock_ref(g_tx, "refs/heads/master"));
+ cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/master", &id, NULL, NULL));
+
+ git_transaction_free(g_tx_with_lock);
+ git_repository_free(g_repo_with_locking_tx);
+}
+
+void test_refs_transactions__commit_unlocks_unmodified_ref(void)
+{
+ git_transaction *second_tx;
+
+ cl_git_pass(git_transaction_new(&second_tx, g_repo));
+ cl_git_pass(git_transaction_lock_ref(second_tx, "refs/heads/master"));
+ cl_git_pass(git_transaction_commit(second_tx));
+
+ /* a transaction must now be able to get the lock */
+ cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
+
+ git_transaction_free(second_tx);
+}
+
+void test_refs_transactions__free_unlocks_unmodified_ref(void)
+{
+ git_transaction *second_tx;
+
+ cl_git_pass(git_transaction_new(&second_tx, g_repo));
+ cl_git_pass(git_transaction_lock_ref(second_tx, "refs/heads/master"));
+ git_transaction_free(second_tx);
+
+ /* a transaction must now be able to get the lock */
+ cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master"));
+}
cl_assert_equal_i(1, array.count);
cl_assert_equal_i(section_count + 2, count_config_entries_match(_repo, "remote\\."));
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_assert_equal_i(0, array.count);
cl_assert_equal_i(section_count + 1, count_config_entries_match(_repo, "remote\\."));
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_assert_equal_i(0, array.count);
cl_assert_equal_i(section_count, count_config_entries_match(_repo, "remote\\."));
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_assert_equal_i(0, array.count);
cl_assert_equal_i(section_count, count_config_entries_match(_repo, "remote\\."));
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_assert_equal_i(1, array.count);
cl_assert_equal_s("+refs/heads/*:refs/remotes/test-new/*", array.strings[0]);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_assert_equal_i(1, array.count);
cl_assert_equal_s("+refs/*:refs/*", array.strings[0]);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_git_pass(git_remote_get_fetch_refspecs(&array, remote));
cl_assert_equal_i(0, array.count);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_git_pass(git_remote_get_fetch_refspecs(&array, remote));
cl_assert_equal_i(0, array.count);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
cl_git_pass(git_remote_get_fetch_refspecs(&array, remote));
cl_assert_equal_i(0, array.count);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
cl_git_pass(git_remote_get_fetch_refspecs(&array, remote));
cl_assert_equal_i(0, array.count);
- git_strarray_free(&array);
+ git_strarray_dispose(&array);
git_remote_free(remote);
}
--- /dev/null
+#include "clar_libgit2.h"
+#include "config/config_helpers.h"
+
+static git_repository *_repo;
+
+#define TEST_URL "http://github.com/libgit2/libgit2.git"
+
+void test_remote_list__initialize(void)
+{
+ _repo = cl_git_sandbox_init("testrepo");
+}
+
+void test_remote_list__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_remote_list__always_checks_disk_config(void)
+{
+ git_repository *repo;
+ git_strarray remotes;
+ git_remote *remote;
+
+ cl_git_pass(git_repository_open(&repo, git_repository_path(_repo)));
+
+ cl_git_pass(git_remote_list(&remotes, _repo));
+ cl_assert_equal_sz(remotes.count, 1);
+ git_strarray_dispose(&remotes);
+
+ cl_git_pass(git_remote_create(&remote, _repo, "valid-name", TEST_URL));
+
+ cl_git_pass(git_remote_list(&remotes, _repo));
+ cl_assert_equal_sz(remotes.count, 2);
+ git_strarray_dispose(&remotes);
+
+ cl_git_pass(git_remote_list(&remotes, repo));
+ cl_assert_equal_sz(remotes.count, 2);
+ git_strarray_dispose(&remotes);
+
+ git_repository_free(repo);
+ git_remote_free(remote);
+}
+
#include "clar_libgit2.h"
#include "sysdir.h"
-#include "fileops.h"
+#include "futils.h"
#include <ctype.h>
static git_buf path = GIT_BUF_INIT;
cl_assert(!git_path_isfile("empty_standard_repo/.git/config"));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(GIT_ABBREV_DEFAULT, val);
git_repository_free(repo);
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(10, val);
git_repository_free(repo);
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(20, val);
git_repository_free(repo);
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(30, val);
git_repository_free(repo);
cl_git_rewritefile("empty_standard_repo/.git/config", "[core]\n\tabbrev = 40\n");
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(40, val);
git_repository_free(repo);
/* with all configs but delete the files ? */
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(40, val);
cl_must_pass(p_unlink("empty_standard_repo/.git/config"));
cl_must_pass(p_unlink("alternate/3/.gitconfig"));
cl_assert(!git_path_isfile("alternate/3/.gitconfig"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(40, val);
git_repository_free(repo);
cl_assert(!git_path_isfile("alternate/3/.gitconfig"));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
- git_repository__cvar_cache_clear(repo);
+ git_repository__configmap_lookup_cache_clear(repo);
val = -1;
- cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV));
+ cl_git_pass(git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_ABBREV));
cl_assert_equal_i(7, val);
git_repository_free(repo);
#include "clar_libgit2.h"
#include "odb.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
#define TEMP_REPO_FOLDER "temprepo/"
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "sysdir.h"
#include <ctype.h>
* from the caller rather than those of the helper. The expression strings
* distinguish between the possible failures within the helper. */
-static void env_pass_(const char *path, const char *file, int line)
+static void env_pass_(const char *path, const char *file, const char *func, int line)
{
git_repository *repo;
- cl_git_expect(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
- cl_git_expect(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
- cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, line);
- cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, line);
- cl_assert_at_line(!git_repository_is_bare(repo), file, line);
+ cl_git_expect(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, func, line);
+ cl_git_expect(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, func, line);
+ cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, func, line);
+ cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, func, line);
+ cl_assert_at_line(!git_repository_is_bare(repo), file, func, line);
git_repository_free(repo);
}
-#define env_pass(path) env_pass_((path), __FILE__, __LINE__)
+#define env_pass(path) env_pass_((path), __FILE__, __func__, __LINE__)
-#define cl_git_fail_at_line(expr, file, line) clar__assert((expr) < 0, file, line, "Expected function call to fail: " #expr, NULL, 1)
+#define cl_git_fail_at_line(expr, file, func, line) clar__assert((expr) < 0, file, func, line, "Expected function call to fail: " #expr, NULL, 1)
-static void env_fail_(const char *path, const char *file, int line)
+static void env_fail_(const char *path, const char *file, const char *func, int line)
{
git_repository *repo;
- cl_git_fail_at_line(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
- cl_git_fail_at_line(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
+ cl_git_fail_at_line(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, func, line);
+ cl_git_fail_at_line(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, func, line);
}
-#define env_fail(path) env_fail_((path), __FILE__, __LINE__)
+#define env_fail(path) env_fail_((path), __FILE__, __func__, __LINE__)
static void env_cd_(
const char *path,
- void (*passfail_)(const char *, const char *, int),
- const char *file, int line)
+ void (*passfail_)(const char *, const char *, const char *, int),
+ const char *file, const char *func, int line)
{
git_buf cwd_buf = GIT_BUF_INIT;
cl_git_pass(git_path_prettify_dir(&cwd_buf, ".", NULL));
cl_must_pass(p_chdir(path));
- passfail_(NULL, file, line);
+ passfail_(NULL, file, func, line);
cl_must_pass(p_chdir(git_buf_cstr(&cwd_buf)));
git_buf_dispose(&cwd_buf);
}
-#define env_cd_pass(path) env_cd_((path), env_pass_, __FILE__, __LINE__)
-#define env_cd_fail(path) env_cd_((path), env_fail_, __FILE__, __LINE__)
+#define env_cd_pass(path) env_cd_((path), env_pass_, __FILE__, __func__, __LINE__)
+#define env_cd_fail(path) env_cd_((path), env_fail_, __FILE__, __func__, __LINE__)
-static void env_check_objects_(bool a, bool t, bool p, const char *file, int line)
+static void env_check_objects_(bool a, bool t, bool p, const char *file, const char *func, int line)
{
git_repository *repo;
git_oid oid_a, oid_t, oid_p;
cl_git_pass(git_oid_fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d"));
cl_git_pass(git_oid_fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08"));
cl_git_pass(git_oid_fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07"));
- cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, line);
+ cl_git_expect(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), 0, file, func, line);
if (a) {
- cl_git_expect(git_object_lookup(&object, repo, &oid_a, GIT_OBJECT_BLOB), 0, file, line);
+ cl_git_expect(git_object_lookup(&object, repo, &oid_a, GIT_OBJECT_BLOB), 0, file, func, line);
git_object_free(object);
} else {
- cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJECT_BLOB), file, line);
+ cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJECT_BLOB), file, func, line);
}
if (t) {
- cl_git_expect(git_object_lookup(&object, repo, &oid_t, GIT_OBJECT_BLOB), 0, file, line);
+ cl_git_expect(git_object_lookup(&object, repo, &oid_t, GIT_OBJECT_BLOB), 0, file, func, line);
git_object_free(object);
} else {
- cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJECT_BLOB), file, line);
+ cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJECT_BLOB), file, func, line);
}
if (p) {
- cl_git_expect(git_object_lookup(&object, repo, &oid_p, GIT_OBJECT_COMMIT), 0, file, line);
+ cl_git_expect(git_object_lookup(&object, repo, &oid_p, GIT_OBJECT_COMMIT), 0, file, func, line);
git_object_free(object);
} else {
- cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJECT_COMMIT), file, line);
+ cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJECT_COMMIT), file, func, line);
}
git_repository_free(repo);
}
-#define env_check_objects(a, t, t2) env_check_objects_((a), (t), (t2), __FILE__, __LINE__)
+#define env_check_objects(a, t, t2) env_check_objects_((a), (t), (t2), __FILE__, __func__, __LINE__)
void test_repo_env__open(void)
{
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
#include "config.h"
#include "path.h"
static git_repository *_repo = NULL;
static git_buf _global_path = GIT_BUF_INIT;
-static mode_t g_umask = 0;
void test_repo_init__initialize(void)
{
_repo = NULL;
- /* load umask if not already loaded */
- if (!g_umask) {
- g_umask = p_umask(022);
- (void)p_umask(g_umask);
- }
-
- git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
- &_global_path);
+ git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
+ &_global_path);
}
void test_repo_init__cleanup(void)
git_config *config, *repo_config;
int val;
- if (!filesystem_supports_symlinks("link"))
+ if (!git_path_supports_symlinks("link"))
cl_skip();
create_tmp_global_config("tmp_global_config", "core.symlinks", "true");
cl_skip();
#else
assert_config_entry_on_init(
- "core.symlinks", filesystem_supports_symlinks("link") ? GIT_ENOTFOUND : false);
+ "core.symlinks", git_path_supports_symlinks("link") ? GIT_ENOTFOUND : false);
#endif
}
assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
}
-void test_repo_init__empty_template_path(void)
-{
- git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
- opts.template_path = "";
-
- cl_git_pass(git_futils_mkdir("foo", 0755, 0));
- cl_git_pass(git_repository_init_ext(&_repo, "foo", &opts));
-
- cleanup_repository("foo");
-}
-
void test_repo_init__extended_0(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
cleanup_repository("root");
}
-#define CLEAR_FOR_CORE_FILEMODE(M) ((M) &= ~0177)
-
-static void assert_hooks_match(
- const char *template_dir,
- const char *repo_dir,
- const char *hook_path,
- bool core_filemode)
-{
- git_buf expected = GIT_BUF_INIT;
- git_buf actual = GIT_BUF_INIT;
- struct stat expected_st, st;
-
- cl_git_pass(git_buf_joinpath(&expected, template_dir, hook_path));
- cl_git_pass(git_path_lstat(expected.ptr, &expected_st));
-
- cl_git_pass(git_buf_joinpath(&actual, repo_dir, hook_path));
- cl_git_pass(git_path_lstat(actual.ptr, &st));
-
- cl_assert(expected_st.st_size == st.st_size);
-
- if (GIT_MODE_TYPE(expected_st.st_mode) != GIT_FILEMODE_LINK) {
- mode_t expected_mode =
- GIT_MODE_TYPE(expected_st.st_mode) |
- (GIT_PERMS_FOR_WRITE(expected_st.st_mode) & ~g_umask);
-
- if (!core_filemode) {
- CLEAR_FOR_CORE_FILEMODE(expected_mode);
- CLEAR_FOR_CORE_FILEMODE(st.st_mode);
- }
-
- cl_assert_equal_i_fmt(expected_mode, st.st_mode, "%07o");
- }
-
- git_buf_dispose(&expected);
- git_buf_dispose(&actual);
-}
-
-static void assert_mode_seems_okay(
- const char *base, const char *path,
- git_filemode_t expect_mode, bool expect_setgid, bool core_filemode)
-{
- git_buf full = GIT_BUF_INIT;
- struct stat st;
-
- cl_git_pass(git_buf_joinpath(&full, base, path));
- cl_git_pass(git_path_lstat(full.ptr, &st));
- git_buf_dispose(&full);
-
- if (!core_filemode) {
- CLEAR_FOR_CORE_FILEMODE(expect_mode);
- CLEAR_FOR_CORE_FILEMODE(st.st_mode);
- expect_setgid = false;
- }
-
- if (S_ISGID != 0)
- cl_assert_equal_b(expect_setgid, (st.st_mode & S_ISGID) != 0);
-
- cl_assert_equal_b(
- GIT_PERMS_IS_EXEC(expect_mode), GIT_PERMS_IS_EXEC(st.st_mode));
-
- cl_assert_equal_i_fmt(
- GIT_MODE_TYPE(expect_mode), GIT_MODE_TYPE(st.st_mode), "%07o");
-}
-
-static const char *template_sandbox(const char *name)
-{
- git_buf hooks_path = GIT_BUF_INIT, link_path = GIT_BUF_INIT,
- dotfile_path = GIT_BUF_INIT;
- const char *path = cl_fixture(name);
-
- cl_fixture_sandbox(name);
-
- /* create a symlink from link.sample to update.sample if the filesystem
- * supports it.
- */
-
- cl_git_pass(git_buf_joinpath(&hooks_path, name, "hooks"));
- cl_git_pass(git_buf_joinpath(&link_path, hooks_path.ptr, "link.sample"));
-
-#ifdef GIT_WIN32
- cl_git_mkfile(link_path.ptr, "#!/bin/sh\necho hello, world\n");
-#else
- cl_must_pass(symlink("update.sample", link_path.ptr));
-#endif
-
- /* create a file starting with a dot */
- cl_git_pass(git_buf_joinpath(&dotfile_path, hooks_path.ptr, ".dotfile"));
- cl_git_mkfile(dotfile_path.ptr, "something\n");
- git_buf_dispose(&dotfile_path);
-
- git_buf_dispose(&dotfile_path);
- git_buf_dispose(&link_path);
- git_buf_dispose(&hooks_path);
-
- return path;
-}
-
-static void configure_templatedir(const char *template_path)
-{
- create_tmp_global_config("tmp_global_path", "init.templatedir", template_path);
-}
-
-static void validate_templates(git_repository *repo, const char *template_path)
-{
- git_buf template_description = GIT_BUF_INIT;
- git_buf repo_description = GIT_BUF_INIT;
- git_buf expected = GIT_BUF_INIT;
- git_buf actual = GIT_BUF_INIT;
- int filemode;
-
- cl_git_pass(git_buf_joinpath(&template_description, template_path,
- "description"));
- cl_git_pass(git_buf_joinpath(&repo_description, git_repository_path(repo),
- "description"));
-
- cl_git_pass(git_futils_readbuffer(&expected, template_description.ptr));
- cl_git_pass(git_futils_readbuffer(&actual, repo_description.ptr));
-
- cl_assert_equal_s(expected.ptr, actual.ptr);
-
- filemode = cl_repo_get_bool(repo, "core.filemode");
-
- assert_hooks_match(
- template_path, git_repository_path(repo),
- "hooks/update.sample", filemode);
-
- assert_hooks_match(
- template_path, git_repository_path(repo),
- "hooks/link.sample", filemode);
-
- assert_hooks_match(
- template_path, git_repository_path(repo),
- "hooks/.dotfile", filemode);
-
- git_buf_dispose(&expected);
- git_buf_dispose(&actual);
- git_buf_dispose(&repo_description);
- git_buf_dispose(&template_description);
-}
-
-void test_repo_init__external_templates_specified_in_options(void)
-{
- git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
-
- cl_set_cleanup(&cleanup_repository, "templated.git");
- template_sandbox("template");
-
- opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
- GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
- opts.template_path = "template";
-
- cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
-
- cl_assert(git_repository_is_bare(_repo));
-
- cl_assert(!git__suffixcmp(git_repository_path(_repo), "/templated.git/"));
-
- validate_templates(_repo, "template");
- cl_fixture_cleanup("template");
-}
-
-void test_repo_init__external_templates_specified_in_config(void)
-{
- git_buf template_path = GIT_BUF_INIT;
-
- git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
-
- cl_set_cleanup(&cleanup_repository, "templated.git");
- template_sandbox("template");
-
- cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(),
- "template"));
-
- configure_templatedir(template_path.ptr);
-
- opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
- GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
-
- cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
-
- validate_templates(_repo, "template");
- cl_fixture_cleanup("template");
-
- git_buf_dispose(&template_path);
-}
-
-void test_repo_init__external_templates_with_leading_dot(void)
-{
- git_buf template_path = GIT_BUF_INIT;
-
- git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
-
- cl_set_cleanup(&cleanup_repository, "templated.git");
- template_sandbox("template");
-
- cl_must_pass(p_rename("template", ".template_with_leading_dot"));
-
- cl_git_pass(git_buf_joinpath(&template_path, clar_sandbox_path(),
- ".template_with_leading_dot"));
-
- configure_templatedir(template_path.ptr);
-
- opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
- GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
-
- cl_git_pass(git_repository_init_ext(&_repo, "templated.git", &opts));
-
- validate_templates(_repo, ".template_with_leading_dot");
- cl_fixture_cleanup(".template_with_leading_dot");
-
- git_buf_dispose(&template_path);
-}
-
-void test_repo_init__extended_with_template_and_shared_mode(void)
-{
- git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
- int filemode = true;
- const char *repo_path = NULL;
-
- cl_set_cleanup(&cleanup_repository, "init_shared_from_tpl");
- template_sandbox("template");
-
- opts.flags = GIT_REPOSITORY_INIT_MKPATH |
- GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
- opts.template_path = "template";
- opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP;
-
- cl_git_pass(git_repository_init_ext(&_repo, "init_shared_from_tpl", &opts));
-
- cl_assert(!git_repository_is_bare(_repo));
- cl_assert(!git__suffixcmp(git_repository_path(_repo), "/init_shared_from_tpl/.git/"));
-
- filemode = cl_repo_get_bool(_repo, "core.filemode");
-
- repo_path = git_repository_path(_repo);
- assert_mode_seems_okay(repo_path, "hooks",
- GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
- assert_mode_seems_okay(repo_path, "info",
- GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
- assert_mode_seems_okay(repo_path, "description",
- GIT_FILEMODE_BLOB, false, filemode);
-
- validate_templates(_repo, "template");
-
- cl_fixture_cleanup("template");
-}
-
void test_repo_init__can_reinit_an_initialized_repository(void)
{
git_repository *reinit;
git_repository_free(repo);
}
-void test_repo_init__nonexistent_paths(void)
+void test_repo_init__nonexisting_directory(void)
{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
git_repository *repo;
+ /*
+ * If creating a repo with non-existing parent directories, then libgit2
+ * will by default create the complete directory hierarchy if using
+ * `git_repository_init`. Thus, let's use the extended version and not
+ * set the `GIT_REPOSITORY_INIT_MKPATH` flag.
+ */
+ cl_git_fail(git_repository_init_ext(&repo, "nonexisting/path", &opts));
+}
+
+void test_repo_init__nonexisting_root(void)
+{
#ifdef GIT_WIN32
+ git_repository *repo;
+
+ /*
+ * This really only depends on the nonexistence of the Q: drive. We
+ * cannot implement the equivalent test on Unix systems, as there is
+ * fundamentally no path that is disconnected from the root directory.
+ */
cl_git_fail(git_repository_init(&repo, "Q:/non/existent/path", 0));
cl_git_fail(git_repository_init(&repo, "Q:\\non\\existent\\path", 0));
#else
- cl_git_fail(git_repository_init(&repo, "/non/existent/path", 0));
+ clar__skip();
+#endif
+}
+
+void test_repo_init__unwriteable_directory(void)
+{
+#ifndef GIT_WIN32
+ git_repository *repo;
+
+ if (geteuid() == 0)
+ clar__skip();
+
+ /*
+ * Create a non-writeable directory so that we cannot create directories
+ * inside of it. The root user has CAP_DAC_OVERRIDE, so he doesn't care
+ * for the directory permissions and thus we need to skip the test if
+ * run as root user.
+ */
+ cl_must_pass(p_mkdir("unwriteable", 0444));
+ cl_git_fail(git_repository_init(&repo, "unwriteable/repo", 0));
+ cl_must_pass(p_rmdir("unwriteable"));
+#else
+ clar__skip();
#endif
}
+
+void test_repo_init__defaultbranch_config(void)
+{
+ git_reference *head;
+
+ cl_set_cleanup(&cleanup_repository, "repo");
+
+ create_tmp_global_config("tmp_global_path", "init.defaultbranch", "my_default_branch");
+
+ cl_git_pass(git_repository_init(&_repo, "repo", 0));
+ cl_git_pass(git_reference_lookup(&head, _repo, "HEAD"));
+
+ cl_assert_equal_s("refs/heads/my_default_branch", git_reference_symbolic_target(head));
+
+ git_reference_free(head);
+}
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "sysdir.h"
#include <ctype.h>
git_config_free(config);
git_repository_free(repo);
+
+ cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+ cl_assert(git_repository_path(repo) != NULL);
+ cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
+ git_repository_free(repo);
+}
+
+void test_repo_open__format_version_1_with_valid_extension(void)
+{
+ git_repository *repo;
+ git_config *config;
+
+ repo = cl_git_sandbox_init("empty_bare.git");
+
+ cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+ cl_git_pass(git_repository_config(&config, repo));
+
+ cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
+ cl_git_pass(git_config_set_int32(config, "extensions.noop", 1));
+
+ git_config_free(config);
+ git_repository_free(repo);
+
+ cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+ cl_assert(git_repository_path(repo) != NULL);
+ cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
+ git_repository_free(repo);
+}
+
+void test_repo_open__format_version_1_with_invalid_extension(void)
+{
+ git_repository *repo;
+ git_config *config;
+
+ repo = cl_git_sandbox_init("empty_bare.git");
+
+ cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+ cl_git_pass(git_repository_config(&config, repo));
+
+ cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
+ cl_git_pass(git_config_set_int32(config, "extensions.invalid", 1));
+
+ git_config_free(config);
+ git_repository_free(repo);
+
cl_git_fail(git_repository_open(&repo, "empty_bare.git"));
+ git_repository_free(repo);
}
void test_repo_open__standard_empty_repo_through_gitdir(void)
cl_fixture_cleanup("attr");
}
+void test_repo_open__check_if_repository(void)
+{
+ cl_git_sandbox_init("empty_standard_repo");
+
+ /* Pass NULL for the output parameter to check for but not open the repo */
+ cl_git_pass(git_repository_open_ext(NULL, "empty_standard_repo", 0, NULL));
+ cl_git_fail(git_repository_open_ext(NULL, "repo_does_not_exist", 0, NULL));
+
+ cl_fixture_cleanup("empty_standard_repo");
+}
+
static void make_gitlink_dir(const char *dir, const char *linktext)
{
git_buf path = GIT_BUF_INIT;
git_repository_free(repo2);
}
+void test_repo_open__with_symlinked_config(void)
+{
+#ifndef GIT_WIN32
+ git_buf path = GIT_BUF_INIT;
+ git_repository *repo;
+ git_config *cfg;
+ int32_t value;
+
+ cl_git_sandbox_init("empty_standard_repo");
+
+ /* Setup .gitconfig as symlink */
+ cl_git_pass(git_futils_mkdir_r("home", 0777));
+ cl_git_mkfile("home/.gitconfig.linked", "[global]\ntest = 4567\n");
+ cl_must_pass(symlink(".gitconfig.linked", "home/.gitconfig"));
+ cl_git_pass(git_path_prettify(&path, "home", NULL));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
+
+ cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
+ cl_git_pass(git_config_open_default(&cfg));
+ cl_git_pass(git_config_get_int32(&value, cfg, "global.test"));
+ cl_assert_equal_i(4567, value);
+
+ git_config_free(cfg);
+ git_repository_free(repo);
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_REMOVE_FILES));
+ cl_sandbox_set_search_path_defaults();
+ git_buf_dispose(&path);
+#endif
+}
+
void test_repo_open__from_git_new_workdir(void)
{
#ifndef GIT_WIN32
for (scan = bad_links; *scan != NULL; scan++) {
make_gitlink_dir("alternate", *scan);
+ repo = NULL;
cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL));
+ cl_assert(repo == NULL);
}
git_futils_rmdir_r("invalid", NULL, GIT_RMDIR_REMOVE_FILES);
git_buf_dispose(&head_path);
}
-int filesystem_supports_symlinks(const char *path)
-{
- struct stat st;
- bool support = 0;
-
- if (p_symlink("target", path) == 0) {
- if (p_lstat(path, &st) == 0 && S_ISLNK(st.st_mode))
- support = 1;
-
- p_unlink(path);
- }
-
- return support;
-}
-
void create_tmp_global_config(const char *dirname, const char *key, const char *val)
{
git_buf path = GIT_BUF_INIT;
extern void make_head_unborn(git_repository* repo, const char *target);
extern void delete_head(git_repository* repo);
-extern int filesystem_supports_symlinks(const char *path);
extern void create_tmp_global_config(const char *path, const char *key, const char *val);
#include "posix.h"
#include "util.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo;
#include "buffer.h"
#include "refs.h"
#include "posix.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *_repo;
static git_buf _path;
--- /dev/null
+#include "clar_libgit2.h"
+
+#include "futils.h"
+#include "repo/repo_helpers.h"
+
+#define CLEAR_FOR_CORE_FILEMODE(M) ((M) &= ~0177)
+
+static git_repository *_repo = NULL;
+static mode_t g_umask = 0;
+static git_buf _global_path = GIT_BUF_INIT;
+
+static const char *fixture_repo;
+static const char *fixture_templates;
+
+void test_repo_template__initialize(void)
+{
+ _repo = NULL;
+
+ /* load umask if not already loaded */
+ if (!g_umask) {
+ g_umask = p_umask(022);
+ (void)p_umask(g_umask);
+ }
+}
+
+void test_repo_template__cleanup(void)
+{
+ git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL,
+ _global_path.ptr);
+ git_buf_dispose(&_global_path);
+
+ cl_fixture_cleanup("tmp_global_path");
+
+ if (fixture_repo) {
+ cl_fixture_cleanup(fixture_repo);
+ fixture_repo = NULL;
+ }
+
+ if (fixture_templates) {
+ cl_fixture_cleanup(fixture_templates);
+ fixture_templates = NULL;
+ }
+
+ git_repository_free(_repo);
+ _repo = NULL;
+}
+
+static void assert_hooks_match(
+ const char *template_dir,
+ const char *repo_dir,
+ const char *hook_path,
+ bool core_filemode)
+{
+ git_buf expected = GIT_BUF_INIT;
+ git_buf actual = GIT_BUF_INIT;
+ struct stat expected_st, st;
+
+ cl_git_pass(git_buf_joinpath(&expected, template_dir, hook_path));
+ cl_git_pass(git_path_lstat(expected.ptr, &expected_st));
+
+ cl_git_pass(git_buf_joinpath(&actual, repo_dir, hook_path));
+ cl_git_pass(git_path_lstat(actual.ptr, &st));
+
+ cl_assert(expected_st.st_size == st.st_size);
+
+ if (GIT_MODE_TYPE(expected_st.st_mode) != GIT_FILEMODE_LINK) {
+ mode_t expected_mode =
+ GIT_MODE_TYPE(expected_st.st_mode) |
+ (GIT_PERMS_FOR_WRITE(expected_st.st_mode) & ~g_umask);
+
+ if (!core_filemode) {
+ CLEAR_FOR_CORE_FILEMODE(expected_mode);
+ CLEAR_FOR_CORE_FILEMODE(st.st_mode);
+ }
+
+ cl_assert_equal_i_fmt(expected_mode, st.st_mode, "%07o");
+ }
+
+ git_buf_dispose(&expected);
+ git_buf_dispose(&actual);
+}
+
+static void assert_mode_seems_okay(
+ const char *base, const char *path,
+ git_filemode_t expect_mode, bool expect_setgid, bool core_filemode)
+{
+ git_buf full = GIT_BUF_INIT;
+ struct stat st;
+
+ cl_git_pass(git_buf_joinpath(&full, base, path));
+ cl_git_pass(git_path_lstat(full.ptr, &st));
+ git_buf_dispose(&full);
+
+ if (!core_filemode) {
+ CLEAR_FOR_CORE_FILEMODE(expect_mode);
+ CLEAR_FOR_CORE_FILEMODE(st.st_mode);
+ expect_setgid = false;
+ }
+
+ if (S_ISGID != 0)
+ cl_assert_equal_b(expect_setgid, (st.st_mode & S_ISGID) != 0);
+
+ cl_assert_equal_b(
+ GIT_PERMS_IS_EXEC(expect_mode), GIT_PERMS_IS_EXEC(st.st_mode));
+
+ cl_assert_equal_i_fmt(
+ GIT_MODE_TYPE(expect_mode), GIT_MODE_TYPE(st.st_mode), "%07o");
+}
+
+static void setup_repo(const char *name, git_repository_init_options *opts)
+{
+ cl_git_pass(git_repository_init_ext(&_repo, name, opts));
+ fixture_repo = name;
+}
+
+static void setup_templates(const char *name, bool setup_globally)
+{
+ git_buf path = GIT_BUF_INIT;
+
+ cl_fixture_sandbox("template");
+ if (strcmp(name, "template"))
+ cl_must_pass(p_rename("template", name));
+
+ fixture_templates = name;
+
+ /*
+ * Create a symlink from link.sample to update.sample if the filesystem
+ * supports it.
+ */
+ cl_git_pass(git_buf_join3(&path, '/', name, "hooks", "link.sample"));
+#ifdef GIT_WIN32
+ cl_git_mkfile(path.ptr, "#!/bin/sh\necho hello, world\n");
+#else
+ cl_must_pass(p_symlink("update.sample", path.ptr));
+#endif
+
+ git_buf_clear(&path);
+
+ /* Create a file starting with a dot */
+ cl_git_pass(git_buf_join3(&path, '/', name, "hooks", ".dotfile"));
+ cl_git_mkfile(path.ptr, "something\n");
+
+ git_buf_clear(&path);
+
+ if (setup_globally) {
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), name));
+ create_tmp_global_config("tmp_global_path", "init.templatedir", path.ptr);
+ }
+
+ git_buf_dispose(&path);
+}
+
+static void validate_templates(git_repository *repo, const char *template_path)
+{
+ git_buf path = GIT_BUF_INIT, expected = GIT_BUF_INIT, actual = GIT_BUF_INIT;
+ int filemode;
+
+ cl_git_pass(git_buf_joinpath(&path, template_path, "description"));
+ cl_git_pass(git_futils_readbuffer(&expected, path.ptr));
+
+ git_buf_clear(&path);
+
+ cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "description"));
+ cl_git_pass(git_futils_readbuffer(&actual, path.ptr));
+
+ cl_assert_equal_s(expected.ptr, actual.ptr);
+
+ filemode = cl_repo_get_bool(repo, "core.filemode");
+
+ assert_hooks_match(
+ template_path, git_repository_path(repo),
+ "hooks/update.sample", filemode);
+ assert_hooks_match(
+ template_path, git_repository_path(repo),
+ "hooks/link.sample", filemode);
+ assert_hooks_match(
+ template_path, git_repository_path(repo),
+ "hooks/.dotfile", filemode);
+
+ git_buf_dispose(&expected);
+ git_buf_dispose(&actual);
+ git_buf_dispose(&path);
+}
+
+void test_repo_template__external_templates_specified_in_options(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
+ GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+ opts.template_path = "template";
+
+ setup_templates("template", false);
+ setup_repo("templated.git", &opts);
+
+ validate_templates(_repo, "template");
+}
+
+void test_repo_template__external_templates_specified_in_config(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
+ GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+
+ setup_templates("template", true);
+ setup_repo("templated.git", &opts);
+
+ validate_templates(_repo, "template");
+}
+
+void test_repo_template__external_templates_with_leading_dot(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_BARE |
+ GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+
+ setup_templates(".template_with_leading_dot", true);
+ setup_repo("templated.git", &opts);
+
+ validate_templates(_repo, ".template_with_leading_dot");
+}
+
+void test_repo_template__extended_with_template_and_shared_mode(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ const char *repo_path;
+ int filemode;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH |
+ GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+ opts.template_path = "template";
+ opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP;
+
+ setup_templates("template", false);
+ setup_repo("init_shared_from_tpl", &opts);
+
+ filemode = cl_repo_get_bool(_repo, "core.filemode");
+
+ repo_path = git_repository_path(_repo);
+ assert_mode_seems_okay(repo_path, "hooks",
+ GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
+ assert_mode_seems_okay(repo_path, "info",
+ GIT_FILEMODE_TREE | GIT_REPOSITORY_INIT_SHARED_GROUP, true, filemode);
+ assert_mode_seems_okay(repo_path, "description",
+ GIT_FILEMODE_BLOB, false, filemode);
+
+ validate_templates(_repo, "template");
+}
+
+void test_repo_template__templated_head_is_used(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ git_buf head = GIT_BUF_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+
+ setup_templates("template", true);
+ cl_git_mkfile("template/HEAD", "foobar\n");
+ setup_repo("repo", &opts);
+
+ cl_git_pass(git_futils_readbuffer(&head, "repo/.git/HEAD"));
+ cl_assert_equal_s("foobar\n", head.ptr);
+
+ git_buf_dispose(&head);
+}
+
+void test_repo_template__initial_head_option_overrides_template_head(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ git_buf head = GIT_BUF_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+ opts.initial_head = "manual";
+
+ setup_templates("template", true);
+ cl_git_mkfile("template/HEAD", "foobar\n");
+ setup_repo("repo", &opts);
+
+ cl_git_pass(git_futils_readbuffer(&head, "repo/.git/HEAD"));
+ cl_assert_equal_s("ref: refs/heads/manual\n", head.ptr);
+
+ git_buf_dispose(&head);
+}
+
+void test_repo_template__empty_template_path(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+ opts.template_path = "";
+
+ setup_repo("foo", &opts);
+}
#include "posix.h"
#include "reset_helpers.h"
#include "path.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *repo;
static git_object *target;
--- /dev/null
+# This is a comment
+ # This is also a comment
+*.java diff=java -crlf myAttr
+
+ NoMyAttr.java !myAttr
+
+ README caveat=unspecified
--- /dev/null
+x\ 1\9d\8fK
+\ 21\10D]ç\14ÙÍB\90$\9dO\aD\ 4Á{¤{:\8cà\18\19¢\vOï\80Ì\ 5¬Õ£àA\15·y¾uí\1cìú"¢\vRA\ f\91Â\88Ì4Ö1\90\84\9cØf/\89\bÅ\14\93]Uϲȣë\18\ 3Ôê\1dX\10
+\8c\ eM¬Ö\aÈ\96,\96\1csFc8©òêS[ô}⩼å£\8f\e\9d78p\9bOÚ\ 6\84\b.%§÷f\8dZÛua\97\7f\uùÝ\e®\83ú\ 2\92JF\80
\ No newline at end of file
--- /dev/null
+x\ 1+)JMU04¶`040031QHÔ+©(aàÙµåJü5¹Ð\85'3ëçÏÙP%ô0Ä\ 3ª ¬à½Ñ}_Õ\89Î\93ÍE\8f{\ 6þ4ºÙ©\9cr\11ª -3'\15¬æ§\9a\7fý^ÃuU\12Û'ËÝ\98\92¿aÝn®ÏP5\19¥é\105÷æ?\8e\9fÉöp¦\1f\87ÍÑ9íÊÚ_$*£\ 1Û\9\88
\ No newline at end of file
--- /dev/null
+x\ 1m\93ÉΣH\10\84çÌSÔÝ\9a\86b©*¤îQ³Û`³c\ 37öÅ\18l\f¿\97§\1fw\8fæÖyH)?)R©PF1].Ý\ 2 \83\85¿\96¹ª@\9e\89\f\11YÄ\95EE\bK\88\90\95\84\17 Ws\90\17\85¼\16K\ eB\8e¥®Ù\\8d\v@Hàê\9ag9ÈU¹P|\14\fª!/p"Ì!ÉD$\8a\84a
+LeëÒN3Ч ÈÙ\f ø^OÓÏ9\eËéRLóõ[1]þ\ 1P \f+\88P\80`Ã@\86¡>ôsàRÍ@Éæ\ 1\ 4EûÈFð½ø\f?\7fµûoðZÿ m®Í½kÀß¿JÖ\8c\9d\r\Ã\ 5Áΰ¥0òµß\9c\ 2\14è¼Ý[\96$Y\91¤Rï4Mß«Ë9?ò¶\1c{·\96·äÙ.\1dµÅ)æuià\1f\10>$¥9{ÿs
+¤X\80w\89¦O\16çi®\19&EÔ4\91<ÏV\ eWr\13}fJ¥ewHÖÄ}«ü\99eo¦\12ÖÖ\r£}ȼ1\ 5<ñrï'\81Æ\ eÝG§\a\8bÞ\84·Ä"î';Lë\ ekÞDN\9doÕ¢sÙ0ÚÝ\834+ºn\9f\1aò¸¯\r\ 5XõUÒyð%èUU\16ùaï\9flkñò°¬§MrzûvìÙuv\19Ì\90CØ{\94âñn6t¨?ýÙ\14\93\1d\ 5^I2:É\egNG+§z©Ï®µ\9a=WÌ=#Ì©\90ßÅæH\ 4b\1fNjì\86\87}Æøq(\f\83\98»\8e¯\)p×½\83\ 1·\ fCóôã\8d\\ frÝ%+\9d\87\90¡¹±e÷"Ùn§g $w¤3\ 6z¢>M\95\88\98F`Òe¤R\80N¢Î\83ú»9´Èæ·*=O&]t6\1fÈ{Îa²\ e\9e\ 3õR~Ìñ\9b°Ëp\7fiSÊNÃ\92 Ý:ø\14@úu*ëBÏÖ\8d¸ÛùÊ8²¸9^Ïr\84\12)Ü´\ 6V
+ÈÉü\86¯Ý÷ ×:»l\1d\7fÛãM1`\88ØÏ\ 6\12\1f|\k¸Kõ£©JÍh ¤ÜHpÖHz\ es%\7f\8b\eåR\ 6çû\88÷v94\aØóv_MAª(½E\ 1+QÑöf¥Q\16sg\1fA÷J\1eî»6ÆFÎú/\97xcòÒ+ß\9fÕ°«q\9ciäËáKè\8b¬\8a_Æç'ÕÄÑ\8cG»U\16eÍQÀºÅy?!îkëØ{+0Æ\92}\10\147|c\ fí^Cíż·£\16/FקXÖ( 2\e9zÂ\1d\6\87M`Ô£b¹Ï\8fsÝ\99F\b1½\e\8f\ fÆÓ\90cÞ¢ñË\eãt÷\83\ 2?\1cy\90¨ÿ2£Ùê\9f\12CIe òoËs¡þ\ 5æÌIª
\ No newline at end of file
-6653ff42313eb5c82806f145391b18a9699800c7
+d93e87a0863c7ec5e772f99e72ca9efddf0ca718
--- /dev/null
+[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
+a=b
multiline comment # with ;\n special chars \
and other stuff !@#" #^^^
back = "this is \ba phrase"
+ dollar = some $sign
+ multiquotes = !ls "x" \
+ ls "# comment2" \
+ $HOME
+ multiquotes2 = !ls "x" \
+ ls "\"# comment2" \
+ $HOME\"
+ multiquotes3 = hi "# ho" there "are #" more \
+quotes
+ quotecomment = hi "# ho" there "are #" more # and a real comment
--- /dev/null
+ref: refs/heads/master
--- /dev/null
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+ precomposeunicode = true
+[remote "origin"]
+ url = /Users/ethomson/libgit2/libgit2-3/tests/resources/crlf.git
+ fetch = +refs/heads/*:refs/remotes/origin/*
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
--- /dev/null
+0000000000000000000000000000000000000000 6b9d5748663795f573ea857276eb2a5f8330efa0 Edward Thomson <ethomson@edwardthomson.com> 1563721143 +0100 clone: from /Users/ethomson/libgit2/libgit2-3/tests/resources/crlf.git
+6b9d5748663795f573ea857276eb2a5f8330efa0 124f4293444614aa8da53be149792c2e43e9bfd9 Edward Thomson <ethomson@edwardthomson.com> 1563721187 +0100 commit: subdir with no translation
--- /dev/null
+0000000000000000000000000000000000000000 6b9d5748663795f573ea857276eb2a5f8330efa0 Edward Thomson <ethomson@edwardthomson.com> 1563721143 +0100 clone: from /Users/ethomson/libgit2/libgit2-3/tests/resources/crlf.git
+6b9d5748663795f573ea857276eb2a5f8330efa0 124f4293444614aa8da53be149792c2e43e9bfd9 Edward Thomson <ethomson@edwardthomson.com> 1563721187 +0100 commit: subdir with no translation
--- /dev/null
+0000000000000000000000000000000000000000 6b9d5748663795f573ea857276eb2a5f8330efa0 Edward Thomson <ethomson@edwardthomson.com> 1563721143 +0100 clone: from /Users/ethomson/libgit2/libgit2-3/tests/resources/crlf.git
--- /dev/null
+x\ 1-\8eÁjÃ0\10D{ÖWì½4H+Ù+C(É¡·þ\84¤]aÓØJU\85\90|}\95\10\98ÃÌ\83\a\93ʺ.\rк·VE@²æÄv\18\99\bÑÈ\94\90²ËvB\1f\18½x\1d=%\89ê\1cªl\rÈsDÒÉx÷H¦!x3\90E\139ÅA\87hPÆdU¸´¹Tøâk¨\f{éký+ÛA\9eàµv©¬\9f`¬\9f\8cC2\13|h¯µê´\9flRá{Ù~/Ë]`\7fzµÃ-Ì¥<ÄÝüÓ]×MÄ\115¼?]ud\86»Ô\ 2ñÖ\ 4òr\12õ\ fÄ&K!
\ No newline at end of file
--- /dev/null
+x\ 1¥\8e]
+Â0\10\84}Î)ö]\90üm\92\82\88/ÞÀ\vl\93--ØDÒ\14¯o\14oàÓÌ|\ 3ÃIJ®K\ 3íÔ¡Uf`"\17\19Ǩ\ 6=Ùhº\1a´ì±Q*¶.8\1e0yñ¤Ê¹\81\e\87\84Þ\ 6ç\8c\1fpBo\98\ 2zí\1d\8f\9ap
+ÆH\9eH
+ÚÛ\*ÜÒ\8bj\82û\Öd8s§\1fwåoñK§XÖ\v(ì£Z©àá(\95\94¢Ó~¶ñ\9f3bÛÇ´Tx-m\86\ UÊÛ\83ÚR²x\ 3jöU×
\ No newline at end of file
--- /dev/null
+x\ 1-\8eKjÄ0\10D³Ö)z\1f2tëcµa\b³\99].¡O\v\9bÄV¢È\84Éé£ \ 3µ¨zð Rݶµ\83ÖøÔ\9b\b\14Avy\ eIfLiò.²Ï\85\9cP\10É\98L0dÑ\17õ\19\9aì\1d<ç¨=&b{Oñ.09o4Å\9c¢Ã\10IË\94\8c
+G_j\83kþ -ÃYÆÚ¾ë~\91\7fðX§T·W ãØ°çÙÂ\vN\88jÐq²K\83·uÿ:Ö_\81óÇ£]na©õ.\9e\96÷áZ²Zk7!<#\ fW\1d½°ú\ 3\ 6²F\81
\ No newline at end of file
--- /dev/null
+x\ 1¥ÎKjÄ0\10\ 4Ьu\8a¾À\ 4},µ\f!d\16É &\ah·ZØ0²\82¬ÁäöQvÙgW¼\82¢¸\96²u°\18\9fz\13\ 1ËÚå9O\1a\17\8fAH¢v£\fÓB\ 3¬ØhÉ9!õEMö\ e\81}\9cÑc\ e\9efÔ\14\9852\1avÙ%ëmä`\f/¬èÑ×Úà=\9dÔ\12ÜÖZ\8eºÃ\8b\fýMoeãV\8f\9aû3×ò
+fr\ e1\ 4\83pÑ\93Öjè8Úå\1f\13ê\9a\12äí.\a\9c[_¡Ðþ\r\9f·\8fK\ 4^©\1d@ûèåükê\aÑ¡Yj
\ No newline at end of file
--- /dev/null
+x\ 1\9dÎÑ\8dÂ0\f\80a\9e3\85ßOwr\93&%\84`\86NàÄ\8e\88 -JÃ!¶\a1\ 2\ 3|¿þ´Îsi`ݸkU\15È¢\12r\b.*{\19z¤\91Ägr>\aɱ\1f\1ccòbn\ui êcæ.x"\12\92\90\82DÎ,\96\a\1d\90ÞN\93Ã,\86ïí¼V\98þu\81©Õ\92.umgØëÌåzLÛïã\1dü\13=@×[k\11\ 3\8dð\83\1d¢I\9fǦßis\12\81m\9d\15bY¸>!\97«næ\ 5J\93LÅ
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eK\ eÂ0\10CYç\14³Gªòk>\12B°à\ 6\`Ò\99Ò.Ú 0\88ëS\107`g?Ë\96\87º,³\80íÝN\1a3°q1\8f\94³·¤=GN:e[R\bäb¡\12 3{6ê\8e\8dW\81\1eÇ\12ÐxLÁ³Ó1ÅÔG¢lqLnk\ fDv(¦(|ÊT\e\è\85\8dà:ÕåQW8ðF?êÄßà纡.G0}0Îz\e\1cìµÑZmt;+üç\8c:\13Aw\9b\ 5EÚ\\9eÂ\ fõ\ 6Y¦Sm
\ No newline at end of file
--- /dev/null
+x\ 1-\8eKNÃ0\18\84Yç\14ÿ\1eµò;\8e\84PYp\82r\81ÿ\155j\13#Ç\80¸=nÅnF3ói¸¬ëÒÀ\85ñ©UUp$\93dKÑbN£\8f\8e\90¼\19)OL\14)`\9aPfµÃ'VÝ\1ap\16CV\89\91Y$ÏSÊ\1c\10Õ³³cÔqVIÑÎ:àW»\94
+çoÝàÜêÂ×ZÚ\ 5^tÅåvâýðÓ\81GÑW°Á9gL\9a2<\ekÌÀ\8f\8fM+¼Ko |\ʺ\97\8f;ó®Nú\bþݱ\ fî\18ï£õ>$8\98Ð1Ã\9b\bìeU eÃú\vórÓ}ø\ 3\ 1.Q¯
\ No newline at end of file
--- /dev/null
+x\ 1¥ÎAJ\ 41\10@Q×9Eí\85!©T:\1d\10\99Y Þ¢ºRí´Ð\13MªAoï\88Gpû\16\9f/mß7\ 3LùÁº*L¬Q\8b\84À)¬\9eyÑEÖU\96\9aÄû\95\16Õ\1a(Jq\1fÜõfP2Q©\8c\151¥\94%¥\99\ 5\89âL\95æ¬Ó$QS \8e\ f»¶\ e¯,\9f\87\ exѾoãz|\ fxzÿ³·ó°¾±ñIÚþ\f\810{\8aS@xôè½»ë}Õô_\11w©U+H»Ùï¾50\1d\86'û2÷\ 3ÿ=T\89
\ No newline at end of file
--- /dev/null
+x\ 1KÊÉOR02aH.ÊIãåÂ$\ 1\9c\9e \1e
\ No newline at end of file
--- /dev/null
+x\ 1-\8eKnÃ0\10C»Ö)f\1f8Ðod\v(\82tÑ\13¤\17\904#Ø\88e\17²ú9~\95 ;\12$\1f\98öR\96\ 6\1aõK«ÌàIû\881*\871;tfÌ9Edb\8a\93&¢1\99LÊ\88ÏPyk \8d\890ù\98\91#\11*Fe\83\ fÆY\1c¥\9a²tÙ±\12á«Í{\85Û7opkuI÷º·\19^¹\84e½¦cøéÀ3ñ\ 5\94ÕZ\1a?\99 NRI)Òócã
+ïÔ[\ 4\1fó^\8e}ëãÎ|¨+?\83\7fwî\83\aÆ\18TÆX\r\83´\1d#Þ\88 ,¿L\90ê°æ!Õ5C^V>Ä\1f=ßR~
\ No newline at end of file
--- /dev/null
+x\ 1¥\8fQ\8a\ 21\10DýÎ)ú\ 2j'\9dd2"\8b\bû)þx\81NÒÃ\bÆ,3\11¯ï¸x\ 3ÿª^AQ\95j)×\ 6ÆÛU\9bD`\10\8eÔiJÖ»>Fc:D´&Rr.\86ì1#÷ÎDõÇ\93Ü\e\10¥,\9c\15\9dH\92î\82PÏ\96}\8fÁ\99\809r\1aPGÅ\8f6Ö ~ó\93§\f\97±\96¹Þa/\v}«\83ü\a\1f·Iµü\80¶DÎx$\ak´\88j¡ËØ&_Ö¨G\eÂ\ eæZ\96¿×\9bÌðÜÂ\9bÁñ|\9aÕ\vǸUë
\ No newline at end of file
--- /dev/null
+# pack-refs with: peeled fully-peeled sorted
+9687e444bcbb85645cb496080434c292f1b57182 refs/remotes/origin/empty-files
+6b9d5748663795f573ea857276eb2a5f8330efa0 refs/remotes/origin/master
--- /dev/null
+9687e444bcbb85645cb496080434c292f1b57182
--- /dev/null
+124f4293444614aa8da53be149792c2e43e9bfd9
--- /dev/null
+ref: refs/remotes/origin/master
--- /dev/null
+521d87c1ec3aef9824daf6d96cc0ae3710766d91
--- /dev/null
+ref: refs/heads/master
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/revert.h"
#include "../merge/merge_helpers.h"
#include "clar_libgit2.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
#include "git2/revert.h"
#include "../merge/merge_helpers.h"
cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 2));
}
+void test_revwalk_basic__push_range_merge_base(void)
+{
+ revwalk_basic_setup_walk(NULL);
+
+ git_revwalk_reset(_walk);
+ git_revwalk_sorting(_walk, 0);
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_revwalk_push_range(_walk, "HEAD...HEAD~2"));
+}
+
+void test_revwalk_basic__push_range_no_range(void)
+{
+ revwalk_basic_setup_walk(NULL);
+
+ git_revwalk_reset(_walk);
+ git_revwalk_sorting(_walk, 0);
+ cl_git_fail_with(GIT_EINVALIDSPEC, git_revwalk_push_range(_walk, "HEAD"));
+}
+
void test_revwalk_basic__push_mixed(void)
{
git_oid oid;
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "stash_helpers.h"
static git_signature *signature;
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "stash_helpers.h"
#include "refs.h"
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "stash_helpers.h"
struct callback_data
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "stash_helpers.h"
static git_repository *repo;
assert_object_oid("refs/stash@{1}", NULL, GIT_OBJECT_COMMIT);
}
+void test_stash_save__multiline_message(void)
+{
+ const char *msg = "This\n\nis a multiline message\n";
+ const git_reflog_entry *entry;
+ git_reflog *reflog;
+
+ assert_object_oid("refs/stash@{0}", NULL, GIT_OBJECT_COMMIT);
+
+ cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, msg, GIT_STASH_DEFAULT));
+
+ cl_git_pass(git_reflog_read(&reflog, repo, "refs/stash"));
+ cl_assert(entry = git_reflog_entry_byindex(reflog, 0));
+ cl_assert_equal_s(git_reflog_entry_message(entry), "On master: This is a multiline message");
+
+ assert_object_oid("refs/stash@{0}", git_oid_tostr_s(&stash_tip_oid), GIT_OBJECT_COMMIT);
+ assert_commit_message_contains("refs/stash@{0}", msg);
+
+ git_reflog_free(reflog);
+}
+
void test_stash_save__cannot_stash_when_there_are_no_local_change(void)
{
git_index *index;
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "stash_helpers.h"
void setup_stash(git_repository *repo, git_signature *signature)
+++ /dev/null
-#include "clar_libgit2.h"
-#include "fileops.h"
-#include "git2/attr.h"
-#include "ignore.h"
-#include "attr.h"
-#include "status_helpers.h"
-
-static git_repository *g_repo = NULL;
-
-void test_status_ignore__initialize(void)
-{
-}
-
-void test_status_ignore__cleanup(void)
-{
- cl_git_sandbox_cleanup();
-}
-
-static void assert_ignored_(
- bool expected, const char *filepath, const char *file, int line)
-{
- int is_ignored = 0;
- cl_git_expect(
- git_status_should_ignore(&is_ignored, g_repo, filepath), 0, file, line);
- clar__assert(
- (expected != 0) == (is_ignored != 0),
- file, line, "expected != is_ignored", filepath, 1);
-}
-#define assert_ignored(expected, filepath) \
- assert_ignored_(expected, filepath, __FILE__, __LINE__)
-#define assert_is_ignored(filepath) \
- assert_ignored_(true, filepath, __FILE__, __LINE__)
-#define refute_is_ignored(filepath) \
- assert_ignored_(false, filepath, __FILE__, __LINE__)
-
-void test_status_ignore__0(void)
-{
- struct {
- const char *path;
- int expected;
- } test_cases[] = {
- /* pattern "ign" from .gitignore */
- { "file", 0 },
- { "ign", 1 },
- { "sub", 0 },
- { "sub/file", 0 },
- { "sub/ign", 1 },
- { "sub/ign/file", 1 },
- { "sub/ign/sub", 1 },
- { "sub/ign/sub/file", 1 },
- { "sub/sub", 0 },
- { "sub/sub/file", 0 },
- { "sub/sub/ign", 1 },
- { "sub/sub/sub", 0 },
- /* pattern "dir/" from .gitignore */
- { "dir", 1 },
- { "dir/", 1 },
- { "sub/dir", 1 },
- { "sub/dir/", 1 },
- { "sub/dir/file", 1 }, /* contained in ignored parent */
- { "sub/sub/dir", 0 }, /* dir is not actually a dir, but a file */
- { NULL, 0 }
- }, *one_test;
-
- g_repo = cl_git_sandbox_init("attr");
-
- for (one_test = test_cases; one_test->path != NULL; one_test++)
- assert_ignored(one_test->expected, one_test->path);
-
- /* confirm that ignore files were cached */
- cl_assert(git_attr_cache__is_cached(
- g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
- cl_assert(git_attr_cache__is_cached(
- g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
-}
-
-
-void test_status_ignore__1(void)
-{
- g_repo = cl_git_sandbox_init("attr");
-
- cl_git_rewritefile("attr/.gitignore", "/*.txt\n/dir/\n");
- git_attr_cache_flush(g_repo);
-
- assert_is_ignored("root_test4.txt");
- refute_is_ignored("sub/subdir_test2.txt");
- assert_is_ignored("dir");
- assert_is_ignored("dir/");
- refute_is_ignored("sub/dir");
- refute_is_ignored("sub/dir/");
-}
-
-void test_status_ignore__empty_repo_with_gitignore_rewrite(void)
-{
- status_entry_single st;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_mkfile(
- "empty_standard_repo/look-ma.txt", "I'm going to be ignored!");
-
- memset(&st, 0, sizeof(st));
- cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
- cl_assert(st.count == 1);
- cl_assert(st.status == GIT_STATUS_WT_NEW);
-
- cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
- cl_assert(st.status == GIT_STATUS_WT_NEW);
-
- refute_is_ignored("look-ma.txt");
-
- cl_git_rewritefile("empty_standard_repo/.gitignore", "*.nomatch\n");
-
- memset(&st, 0, sizeof(st));
- cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
- cl_assert(st.count == 2);
- cl_assert(st.status == GIT_STATUS_WT_NEW);
-
- cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
- cl_assert(st.status == GIT_STATUS_WT_NEW);
-
- refute_is_ignored("look-ma.txt");
-
- cl_git_rewritefile("empty_standard_repo/.gitignore", "*.txt\n");
-
- memset(&st, 0, sizeof(st));
- cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
- cl_assert(st.count == 2);
- cl_assert(st.status == GIT_STATUS_IGNORED);
-
- cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt"));
- cl_assert(st.status == GIT_STATUS_IGNORED);
-
- assert_is_ignored("look-ma.txt");
-}
-
-void test_status_ignore__ignore_pattern_contains_space(void)
-{
- unsigned int flags;
- const mode_t mode = 0777;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
- cl_git_rewritefile("empty_standard_repo/.gitignore", "foo bar.txt\n");
-
- cl_git_mkfile(
- "empty_standard_repo/foo bar.txt", "I'm going to be ignored!");
-
- cl_git_pass(git_status_file(&flags, g_repo, "foo bar.txt"));
- cl_assert(flags == GIT_STATUS_IGNORED);
-
- cl_git_pass(git_futils_mkdir_r("empty_standard_repo/foo", mode));
- cl_git_mkfile("empty_standard_repo/foo/look-ma.txt", "I'm not going to be ignored!");
-
- cl_git_pass(git_status_file(&flags, g_repo, "foo/look-ma.txt"));
- cl_assert(flags == GIT_STATUS_WT_NEW);
-}
-
-void test_status_ignore__ignore_pattern_ignorecase(void)
-{
- unsigned int flags;
- bool ignore_case;
- git_index *index;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
- cl_git_rewritefile("empty_standard_repo/.gitignore", "a.txt\n");
-
- cl_git_mkfile("empty_standard_repo/A.txt", "Differs in case");
-
- cl_git_pass(git_repository_index(&index, g_repo));
- ignore_case = (git_index_caps(index) & GIT_INDEX_CAPABILITY_IGNORE_CASE) != 0;
- git_index_free(index);
-
- cl_git_pass(git_status_file(&flags, g_repo, "A.txt"));
- cl_assert(flags == ignore_case ? GIT_STATUS_IGNORED : GIT_STATUS_WT_NEW);
-}
-
-void test_status_ignore__subdirectories(void)
-{
- status_entry_single st;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_mkfile(
- "empty_standard_repo/ignore_me", "I'm going to be ignored!");
-
- cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n");
-
- memset(&st, 0, sizeof(st));
- cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
- cl_assert_equal_i(2, st.count);
- cl_assert(st.status == GIT_STATUS_IGNORED);
-
- cl_git_pass(git_status_file(&st.status, g_repo, "ignore_me"));
- cl_assert(st.status == GIT_STATUS_IGNORED);
-
- assert_is_ignored("ignore_me");
-
- /* I've changed libgit2 so that the behavior here now differs from
- * core git but seems to make more sense. In core git, the following
- * items are skipped completed, even if --ignored is passed to status.
- * It you mirror these steps and run "git status -uall --ignored" then
- * you will not see "test/ignore_me/" in the results.
- *
- * However, we had a couple reports of this as a bug, plus there is a
- * similar circumstance where we were differing for core git when you
- * used a rooted path for an ignore, so I changed this behavior.
- */
- cl_git_pass(git_futils_mkdir_r(
- "empty_standard_repo/test/ignore_me", 0775));
- cl_git_mkfile(
- "empty_standard_repo/test/ignore_me/file", "I'm going to be ignored!");
- cl_git_mkfile(
- "empty_standard_repo/test/ignore_me/file2", "Me, too!");
-
- memset(&st, 0, sizeof(st));
- cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st));
- cl_assert_equal_i(3, st.count);
-
- cl_git_pass(git_status_file(&st.status, g_repo, "test/ignore_me/file"));
- cl_assert(st.status == GIT_STATUS_IGNORED);
-
- assert_is_ignored("test/ignore_me/file");
-}
-
-static void make_test_data(const char *reponame, const char **files)
-{
- const char **scan;
- size_t repolen = strlen(reponame) + 1;
-
- g_repo = cl_git_sandbox_init(reponame);
-
- for (scan = files; *scan != NULL; ++scan) {
- cl_git_pass(git_futils_mkdir_relative(
- *scan + repolen, reponame,
- 0777, GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST, NULL));
- cl_git_mkfile(*scan, "contents");
- }
-}
-
-static const char *test_repo_1 = "empty_standard_repo";
-static const char *test_files_1[] = {
- "empty_standard_repo/dir/a/ignore_me",
- "empty_standard_repo/dir/b/ignore_me",
- "empty_standard_repo/dir/ignore_me",
- "empty_standard_repo/ignore_also/file",
- "empty_standard_repo/ignore_me",
- "empty_standard_repo/test/ignore_me/file",
- "empty_standard_repo/test/ignore_me/file2",
- "empty_standard_repo/test/ignore_me/and_me/file",
- NULL
-};
-
-void test_status_ignore__subdirectories_recursion(void)
-{
- /* Let's try again with recursing into ignored dirs turned on */
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
- static const char *paths_r[] = {
- ".gitignore",
- "dir/a/ignore_me",
- "dir/b/ignore_me",
- "dir/ignore_me",
- "ignore_also/file",
- "ignore_me",
- "test/ignore_me/and_me/file",
- "test/ignore_me/file",
- "test/ignore_me/file2",
- };
- static const unsigned int statuses_r[] = {
- GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- };
- static const char *paths_nr[] = {
- ".gitignore",
- "dir/a/ignore_me",
- "dir/b/ignore_me",
- "dir/ignore_me",
- "ignore_also/",
- "ignore_me",
- "test/ignore_me/",
- };
- static const unsigned int statuses_nr[] = {
- GIT_STATUS_WT_NEW,
- GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- };
-
- make_test_data(test_repo_1, test_files_1);
- cl_git_rewritefile("empty_standard_repo/.gitignore", "ignore_me\n/ignore_also\n");
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 9;
- counts.expected_paths = paths_r;
- counts.expected_statuses = statuses_r;
-
- opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
-
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
-
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 7;
- counts.expected_paths = paths_nr;
- counts.expected_statuses = statuses_nr;
-
- opts.flags = GIT_STATUS_OPT_DEFAULTS;
-
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
-}
-
-void test_status_ignore__subdirectories_not_at_root(void)
-{
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
- static const char *paths_1[] = {
- "dir/.gitignore",
- "dir/a/ignore_me",
- "dir/b/ignore_me",
- "dir/ignore_me",
- "ignore_also/file",
- "ignore_me",
- "test/.gitignore",
- "test/ignore_me/and_me/file",
- "test/ignore_me/file",
- "test/ignore_me/file2",
- };
- static const unsigned int statuses_1[] = {
- GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- GIT_STATUS_IGNORED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
- GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
- };
-
- make_test_data(test_repo_1, test_files_1);
- cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "ignore_me\n/ignore_also\n");
- cl_git_rewritefile("empty_standard_repo/test/.gitignore", "and_me\n");
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 10;
- counts.expected_paths = paths_1;
- counts.expected_statuses = statuses_1;
-
- opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
-
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
-}
-
-void test_status_ignore__leading_slash_ignores(void)
-{
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
- static const char *paths_2[] = {
- "dir/.gitignore",
- "dir/a/ignore_me",
- "dir/b/ignore_me",
- "dir/ignore_me",
- "ignore_also/file",
- "ignore_me",
- "test/.gitignore",
- "test/ignore_me/and_me/file",
- "test/ignore_me/file",
- "test/ignore_me/file2",
- };
- static const unsigned int statuses_2[] = {
- GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
- GIT_STATUS_IGNORED, GIT_STATUS_IGNORED, GIT_STATUS_IGNORED,
- GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW,
- };
-
- make_test_data(test_repo_1, test_files_1);
-
- cl_fake_home();
- cl_git_mkfile("home/.gitignore", "/ignore_me\n");
- {
- git_config *cfg;
- cl_git_pass(git_repository_config(&cfg, g_repo));
- cl_git_pass(git_config_set_string(
- cfg, "core.excludesfile", "~/.gitignore"));
- git_config_free(cfg);
- }
-
- cl_git_rewritefile("empty_standard_repo/.git/info/exclude", "/ignore_also\n");
- cl_git_rewritefile("empty_standard_repo/dir/.gitignore", "/ignore_me\n");
- cl_git_rewritefile("empty_standard_repo/test/.gitignore", "/and_me\n");
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 10;
- counts.expected_paths = paths_2;
- counts.expected_statuses = statuses_2;
-
- opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
-
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
-}
-
-void test_status_ignore__contained_dir_with_matching_name(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/subdir_match/aaa/subdir_match/file",
- "empty_standard_repo/subdir_match/zzz_ignoreme",
- NULL
- };
- static const char *expected_paths[] = {
- "subdir_match/.gitignore",
- "subdir_match/aaa/subdir_match/file",
- "subdir_match/zzz_ignoreme",
- };
- static const unsigned int expected_statuses[] = {
- GIT_STATUS_WT_NEW, GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED
- };
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/subdir_match/.gitignore", "*_ignoreme\n");
-
- refute_is_ignored("subdir_match/aaa/subdir_match/file");
- assert_is_ignored("subdir_match/zzz_ignoreme");
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 3;
- counts.expected_paths = expected_paths;
- counts.expected_statuses = expected_statuses;
-
- opts.flags = GIT_STATUS_OPT_DEFAULTS | GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
-
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
-}
-
-void test_status_ignore__trailing_slash_star(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/file",
- "empty_standard_repo/subdir/file",
- "empty_standard_repo/subdir/sub2/sub3/file",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/subdir/.gitignore", "/**/*\n");
-
- refute_is_ignored("file");
- assert_is_ignored("subdir/sub2/sub3/file");
- assert_is_ignored("subdir/file");
-}
-
-void test_status_ignore__adding_internal_ignores(void)
-{
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- refute_is_ignored("one.txt");
- refute_is_ignored("two.bar");
-
- cl_git_pass(git_ignore_add_rule(g_repo, "*.nomatch\n"));
-
- refute_is_ignored("one.txt");
- refute_is_ignored("two.bar");
-
- cl_git_pass(git_ignore_add_rule(g_repo, "*.txt\n"));
-
- assert_is_ignored("one.txt");
- refute_is_ignored("two.bar");
-
- cl_git_pass(git_ignore_add_rule(g_repo, "*.bar\n"));
-
- assert_is_ignored("one.txt");
- assert_is_ignored("two.bar");
-
- cl_git_pass(git_ignore_clear_internal_rules(g_repo));
-
- refute_is_ignored("one.txt");
- refute_is_ignored("two.bar");
-
- cl_git_pass(git_ignore_add_rule(
- g_repo, "multiple\n*.rules\n# comment line\n*.bar\n"));
-
- refute_is_ignored("one.txt");
- assert_is_ignored("two.bar");
-}
-
-void test_status_ignore__add_internal_as_first_thing(void)
-{
- const char *add_me = "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/\ntmp/\n*.tmp\n\n";
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_pass(git_ignore_add_rule(g_repo, add_me));
-
- assert_is_ignored("one.tmp");
- refute_is_ignored("two.bar");
-}
-
-void test_status_ignore__internal_ignores_inside_deep_paths(void)
-{
- const char *add_me = "Debug\nthis/is/deep\npatterned*/dir\n";
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_pass(git_ignore_add_rule(g_repo, add_me));
-
- assert_is_ignored("Debug");
- assert_is_ignored("and/Debug");
- assert_is_ignored("really/Debug/this/file");
- assert_is_ignored("Debug/what/I/say");
-
- refute_is_ignored("and/NoDebug");
- refute_is_ignored("NoDebug/this");
- refute_is_ignored("please/NoDebug/this");
-
- assert_is_ignored("this/is/deep");
- /* pattern containing slash gets FNM_PATHNAME so all slashes must match */
- refute_is_ignored("and/this/is/deep");
- assert_is_ignored("this/is/deep/too");
- /* pattern containing slash gets FNM_PATHNAME so all slashes must match */
- refute_is_ignored("but/this/is/deep/and/ignored");
-
- refute_is_ignored("this/is/not/deep");
- refute_is_ignored("is/this/not/as/deep");
- refute_is_ignored("this/is/deepish");
- refute_is_ignored("xthis/is/deep");
-}
-
-void test_status_ignore__automatically_ignore_bad_files(void)
-{
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- assert_is_ignored(".git");
- assert_is_ignored("this/file/.");
- assert_is_ignored("path/../funky");
- refute_is_ignored("path/whatever.c");
-
- cl_git_pass(git_ignore_add_rule(g_repo, "*.c\n"));
-
- assert_is_ignored(".git");
- assert_is_ignored("this/file/.");
- assert_is_ignored("path/../funky");
- assert_is_ignored("path/whatever.c");
-
- cl_git_pass(git_ignore_clear_internal_rules(g_repo));
-
- assert_is_ignored(".git");
- assert_is_ignored("this/file/.");
- assert_is_ignored("path/../funky");
- refute_is_ignored("path/whatever.c");
-}
-
-void test_status_ignore__filenames_with_special_prefixes_do_not_interfere_with_status_retrieval(void)
-{
- status_entry_single st;
- char *test_cases[] = {
- "!file",
- "#blah",
- "[blah]",
- "[attr]",
- "[attr]blah",
- NULL
- };
- int i;
-
- for (i = 0; *(test_cases + i) != NULL; i++) {
- git_buf file = GIT_BUF_INIT;
- char *file_name = *(test_cases + i);
- git_repository *repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_pass(git_buf_joinpath(&file, "empty_standard_repo", file_name));
- cl_git_mkfile(git_buf_cstr(&file), "Please don't ignore me!");
-
- memset(&st, 0, sizeof(st));
- cl_git_pass(git_status_foreach(repo, cb_status__single, &st));
- cl_assert(st.count == 1);
- cl_assert(st.status == GIT_STATUS_WT_NEW);
-
- cl_git_pass(git_status_file(&st.status, repo, file_name));
- cl_assert(st.status == GIT_STATUS_WT_NEW);
-
- cl_git_sandbox_cleanup();
- git_buf_dispose(&file);
- }
-}
-
-void test_status_ignore__issue_1766_negated_ignores(void)
-{
- unsigned int status;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_pass(git_futils_mkdir_r(
- "empty_standard_repo/a", 0775));
- cl_git_mkfile(
- "empty_standard_repo/a/.gitignore", "*\n!.gitignore\n");
- cl_git_mkfile(
- "empty_standard_repo/a/ignoreme", "I should be ignored\n");
-
- refute_is_ignored("a/.gitignore");
- assert_is_ignored("a/ignoreme");
-
- cl_git_pass(git_futils_mkdir_r(
- "empty_standard_repo/b", 0775));
- cl_git_mkfile(
- "empty_standard_repo/b/.gitignore", "*\n!.gitignore\n");
- cl_git_mkfile(
- "empty_standard_repo/b/ignoreme", "I should be ignored\n");
-
- refute_is_ignored("b/.gitignore");
- assert_is_ignored("b/ignoreme");
-
- /* shouldn't have changed results from first couple either */
- refute_is_ignored("a/.gitignore");
- assert_is_ignored("a/ignoreme");
-
- /* status should find the two ignore files and nothing else */
-
- cl_git_pass(git_status_file(&status, g_repo, "a/.gitignore"));
- cl_assert_equal_i(GIT_STATUS_WT_NEW, (int)status);
-
- cl_git_pass(git_status_file(&status, g_repo, "a/ignoreme"));
- cl_assert_equal_i(GIT_STATUS_IGNORED, (int)status);
-
- cl_git_pass(git_status_file(&status, g_repo, "b/.gitignore"));
- cl_assert_equal_i(GIT_STATUS_WT_NEW, (int)status);
-
- cl_git_pass(git_status_file(&status, g_repo, "b/ignoreme"));
- cl_assert_equal_i(GIT_STATUS_IGNORED, (int)status);
-
- {
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
- static const char *paths[] = {
- "a/.gitignore",
- "a/ignoreme",
- "b/.gitignore",
- "b/ignoreme",
- };
- static const unsigned int statuses[] = {
- GIT_STATUS_WT_NEW,
- GIT_STATUS_IGNORED,
- GIT_STATUS_WT_NEW,
- GIT_STATUS_IGNORED,
- };
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 4;
- counts.expected_paths = paths;
- counts.expected_statuses = statuses;
-
- opts.flags = GIT_STATUS_OPT_DEFAULTS;
-
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
- }
-}
-
-static void add_one_to_index(const char *file)
-{
- git_index *index;
- cl_git_pass(git_repository_index(&index, g_repo));
- cl_git_pass(git_index_add_bypath(index, file));
- git_index_free(index);
-}
-
-/* Some further broken scenarios that have been reported */
-void test_status_ignore__more_breakage(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/d1/pfx-d2/d3/d4/d5/tracked",
- "empty_standard_repo/d1/pfx-d2/d3/d4/d5/untracked",
- "empty_standard_repo/d1/pfx-d2/d3/d4/untracked",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "/d1/pfx-*\n"
- "!/d1/pfx-d2/\n"
- "/d1/pfx-d2/*\n"
- "!/d1/pfx-d2/d3/\n"
- "/d1/pfx-d2/d3/*\n"
- "!/d1/pfx-d2/d3/d4/\n");
- add_one_to_index("d1/pfx-d2/d3/d4/d5/tracked");
-
- {
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
- static const char *files[] = {
- ".gitignore",
- "d1/pfx-d2/d3/d4/d5/tracked",
- "d1/pfx-d2/d3/d4/d5/untracked",
- "d1/pfx-d2/d3/d4/untracked",
- };
- static const unsigned int statuses[] = {
- GIT_STATUS_WT_NEW,
- GIT_STATUS_INDEX_NEW,
- GIT_STATUS_WT_NEW,
- GIT_STATUS_WT_NEW,
- };
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 4;
- counts.expected_paths = files;
- counts.expected_statuses = statuses;
- opts.flags = GIT_STATUS_OPT_DEFAULTS |
- GIT_STATUS_OPT_INCLUDE_IGNORED |
- GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
- }
-
- refute_is_ignored("d1/pfx-d2/d3/d4/d5/tracked");
- refute_is_ignored("d1/pfx-d2/d3/d4/d5/untracked");
- refute_is_ignored("d1/pfx-d2/d3/d4/untracked");
-}
-
-void test_status_ignore__negative_ignores_inside_ignores(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/top/mid/btm/tracked",
- "empty_standard_repo/top/mid/btm/untracked",
- "empty_standard_repo/zoo/bar",
- "empty_standard_repo/zoo/foo/bar",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "top\n"
- "!top/mid/btm\n"
- "zoo/*\n"
- "!zoo/bar\n"
- "!zoo/foo/bar\n");
- add_one_to_index("top/mid/btm/tracked");
-
- {
- git_status_options opts = GIT_STATUS_OPTIONS_INIT;
- status_entry_counts counts;
- static const char *files[] = {
- ".gitignore", "top/mid/btm/tracked", "top/mid/btm/untracked",
- "zoo/bar", "zoo/foo/bar",
- };
- static const unsigned int statuses[] = {
- GIT_STATUS_WT_NEW, GIT_STATUS_INDEX_NEW, GIT_STATUS_IGNORED,
- GIT_STATUS_WT_NEW, GIT_STATUS_IGNORED,
- };
-
- memset(&counts, 0x0, sizeof(status_entry_counts));
- counts.expected_entry_count = 5;
- counts.expected_paths = files;
- counts.expected_statuses = statuses;
- opts.flags = GIT_STATUS_OPT_DEFAULTS |
- GIT_STATUS_OPT_INCLUDE_IGNORED |
- GIT_STATUS_OPT_RECURSE_IGNORED_DIRS;
- cl_git_pass(git_status_foreach_ext(
- g_repo, &opts, cb_status__normal, &counts));
-
- cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
- cl_assert_equal_i(0, counts.wrong_status_flags_count);
- cl_assert_equal_i(0, counts.wrong_sorted_path);
- }
-
- assert_is_ignored("top/mid/btm/tracked");
- assert_is_ignored("top/mid/btm/untracked");
- refute_is_ignored("foo/bar");
-}
-
-void test_status_ignore__negative_ignores_in_slash_star(void)
-{
- git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
- git_status_list *list;
- int found_look_ma = 0, found_what_about = 0;
- size_t i;
- static const char *test_files[] = {
- "empty_standard_repo/bin/look-ma.txt",
- "empty_standard_repo/bin/what-about-me.txt",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "bin/*\n"
- "!bin/w*\n");
-
- assert_is_ignored("bin/look-ma.txt");
- refute_is_ignored("bin/what-about-me.txt");
-
- status_opts.flags = GIT_STATUS_OPT_DEFAULTS;
- cl_git_pass(git_status_list_new(&list, g_repo, &status_opts));
- for (i = 0; i < git_status_list_entrycount(list); i++) {
- const git_status_entry *entry = git_status_byindex(list, i);
-
- if (!strcmp("bin/look-ma.txt", entry->index_to_workdir->new_file.path))
- found_look_ma = 1;
-
- if (!strcmp("bin/what-about-me.txt", entry->index_to_workdir->new_file.path))
- found_what_about = 1;
- }
- git_status_list_free(list);
-
- cl_assert(found_look_ma);
- cl_assert(found_what_about);
-}
-
-void test_status_ignore__negative_ignores_without_trailing_slash_inside_ignores(void)
-{
- git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
- git_status_list *list;
- int found_parent_file = 0, found_parent_child1_file = 0, found_parent_child2_file = 0;
- size_t i;
- static const char *test_files[] = {
- "empty_standard_repo/parent/file.txt",
- "empty_standard_repo/parent/force.txt",
- "empty_standard_repo/parent/child1/file.txt",
- "empty_standard_repo/parent/child2/file.txt",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "parent/*\n"
- "!parent/force.txt\n"
- "!parent/child1\n"
- "!parent/child2/\n");
-
- add_one_to_index("parent/force.txt");
-
- assert_is_ignored("parent/file.txt");
- refute_is_ignored("parent/force.txt");
- refute_is_ignored("parent/child1/file.txt");
- refute_is_ignored("parent/child2/file.txt");
-
- status_opts.flags = GIT_STATUS_OPT_DEFAULTS;
- cl_git_pass(git_status_list_new(&list, g_repo, &status_opts));
- for (i = 0; i < git_status_list_entrycount(list); i++) {
- const git_status_entry *entry = git_status_byindex(list, i);
-
- if (!entry->index_to_workdir)
- continue;
-
- if (!strcmp("parent/file.txt", entry->index_to_workdir->new_file.path))
- found_parent_file = 1;
-
- if (!strcmp("parent/force.txt", entry->index_to_workdir->new_file.path))
- found_parent_file = 1;
-
- if (!strcmp("parent/child1/file.txt", entry->index_to_workdir->new_file.path))
- found_parent_child1_file = 1;
-
- if (!strcmp("parent/child2/file.txt", entry->index_to_workdir->new_file.path))
- found_parent_child2_file = 1;
- }
- git_status_list_free(list);
-
- cl_assert(found_parent_file);
- cl_assert(found_parent_child1_file);
- cl_assert(found_parent_child2_file);
-}
-
-void test_status_ignore__negative_directory_ignores(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/parent/child1/bar.txt",
- "empty_standard_repo/parent/child2/bar.txt",
- "empty_standard_repo/parent/child3/foo.txt",
- "empty_standard_repo/parent/child4/bar.txt",
- "empty_standard_repo/parent/nested/child5/bar.txt",
- "empty_standard_repo/parent/nested/child6/bar.txt",
- "empty_standard_repo/parent/nested/child7/bar.txt",
- "empty_standard_repo/padded_parent/child8/bar.txt",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "foo.txt\n"
- "parent/child1\n"
- "parent/child2\n"
- "parent/child4\n"
- "parent/nested/child5\n"
- "nested/child6\n"
- "nested/child7\n"
- "padded_parent/child8\n"
- /* test simple exact match */
- "!parent/child1\n"
- /* test negating file without negating dir */
- "!parent/child2/bar.txt\n"
- /* test negative pattern on dir with its content
- * being ignored */
- "!parent/child3\n"
- /* test with partial match at end */
- "!child4\n"
- /* test with partial match with '/' at end */
- "!nested/child5\n"
- /* test with complete match */
- "!nested/child6\n"
- /* test with trailing '/' */
- "!child7/\n"
- /* test with partial dir match */
- "!_parent/child8\n");
-
- refute_is_ignored("parent/child1/bar.txt");
- assert_is_ignored("parent/child2/bar.txt");
- assert_is_ignored("parent/child3/foo.txt");
- refute_is_ignored("parent/child4/bar.txt");
- assert_is_ignored("parent/nested/child5/bar.txt");
- refute_is_ignored("parent/nested/child6/bar.txt");
- refute_is_ignored("parent/nested/child7/bar.txt");
- assert_is_ignored("padded_parent/child8/bar.txt");
-}
-
-void test_status_ignore__unignore_entry_in_ignored_dir(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/bar.txt",
- "empty_standard_repo/parent/bar.txt",
- "empty_standard_repo/parent/child/bar.txt",
- "empty_standard_repo/nested/parent/child/bar.txt",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "bar.txt\n"
- "!parent/child/bar.txt\n");
-
- assert_is_ignored("bar.txt");
- assert_is_ignored("parent/bar.txt");
- refute_is_ignored("parent/child/bar.txt");
- assert_is_ignored("nested/parent/child/bar.txt");
-}
-
-void test_status_ignore__do_not_unignore_basename_prefix(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/foo_bar.txt",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "foo_bar.txt\n"
- "!bar.txt\n");
-
- assert_is_ignored("foo_bar.txt");
-}
-
-void test_status_ignore__filename_with_cr(void)
-{
- int ignored;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
- cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\r\n");
-
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
- cl_assert_equal_i(1, ignored);
-
- cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\n");
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
- cl_assert_equal_i(1, ignored);
-
- cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\n");
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
- cl_assert_equal_i(1, ignored);
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
- cl_assert_equal_i(0, ignored);
-
- cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\r\n");
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
- cl_assert_equal_i(1, ignored);
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
- cl_assert_equal_i(0, ignored);
-
- cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\n");
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
- cl_assert_equal_i(0, ignored);
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon"));
- cl_assert_equal_i(1, ignored);
-}
-
-void test_status_ignore__subdir_doesnt_match_above(void)
-{
- int ignored, icase = 0, error;
- git_config *cfg;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_pass(git_repository_config_snapshot(&cfg, g_repo));
- error = git_config_get_bool(&icase, cfg, "core.ignorecase");
- git_config_free(cfg);
- if (error == GIT_ENOTFOUND)
- error = 0;
-
- cl_git_pass(error);
-
- cl_git_pass(p_mkdir("empty_standard_repo/src", 0777));
- cl_git_pass(p_mkdir("empty_standard_repo/src/src", 0777));
- cl_git_mkfile("empty_standard_repo/src/.gitignore", "src\n");
- cl_git_mkfile("empty_standard_repo/.gitignore", "");
-
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/test.txt"));
- cl_assert_equal_i(0, ignored);
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/src/test.txt"));
- cl_assert_equal_i(1, ignored);
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/foo/test.txt"));
- cl_assert_equal_i(0, ignored);
-
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "SRC/src/test.txt"));
- cl_assert_equal_i(icase, ignored);
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "src/SRC/test.txt"));
- cl_assert_equal_i(icase, ignored);
-}
-
-void test_status_ignore__negate_exact_previous(void)
-{
- int ignored;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_mkfile("empty_standard_repo/.gitignore", "*.com\ntags\n!tags/\n.buildpath");
- cl_git_mkfile("empty_standard_repo/.buildpath", "");
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, ".buildpath"));
- cl_assert_equal_i(1, ignored);
-}
-
-void test_status_ignore__negate_starstar(void)
-{
- int ignored;
-
- g_repo = cl_git_sandbox_init("empty_standard_repo");
-
- cl_git_mkfile("empty_standard_repo/.gitignore",
- "code/projects/**/packages/*\n"
- "!code/projects/**/packages/repositories.config");
-
- cl_git_pass(git_futils_mkdir_r("empty_standard_repo/code/projects/foo/bar/packages", 0777));
- cl_git_mkfile("empty_standard_repo/code/projects/foo/bar/packages/repositories.config", "");
-
- cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "code/projects/foo/bar/packages/repositories.config"));
- cl_assert_equal_i(0, ignored);
-}
-
-void test_status_ignore__ignore_all_toplevel_dirs_include_files(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/README.md",
- "empty_standard_repo/src/main.c",
- "empty_standard_repo/src/foo/foo.c",
- "empty_standard_repo/dist/foo.o",
- "empty_standard_repo/dist/main.o",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "/*/\n"
- "!/src\n");
-
- assert_is_ignored("dist/foo.o");
- assert_is_ignored("dist/main.o");
-
- refute_is_ignored("README.md");
- refute_is_ignored("src/foo.c");
- refute_is_ignored("src/foo/foo.c");
-}
-
-void test_status_ignore__subdir_ignore_all_toplevel_dirs_include_files(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/project/README.md",
- "empty_standard_repo/project/src/main.c",
- "empty_standard_repo/project/src/foo/foo.c",
- "empty_standard_repo/project/dist/foo.o",
- "empty_standard_repo/project/dist/main.o",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/project/.gitignore",
- "/*/\n"
- "!/src\n");
-
- assert_is_ignored("project/dist/foo.o");
- assert_is_ignored("project/dist/main.o");
-
- refute_is_ignored("project/src/foo.c");
- refute_is_ignored("project/src/foo/foo.c");
- refute_is_ignored("project/README.md");
-}
-
-void test_status_ignore__subdir_ignore_everything_except_certain_files(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/project/README.md",
- "empty_standard_repo/project/some_file",
- "empty_standard_repo/project/src/main.c",
- "empty_standard_repo/project/src/foo/foo.c",
- "empty_standard_repo/project/dist/foo.o",
- "empty_standard_repo/project/dist/main.o",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/project/.gitignore",
- "/*\n"
- "!/src\n"
- "!README.md\n");
-
- assert_is_ignored("project/some_file");
- assert_is_ignored("project/dist/foo.o");
- assert_is_ignored("project/dist/main.o");
-
- refute_is_ignored("project/README.md");
- refute_is_ignored("project/src/foo.c");
- refute_is_ignored("project/src/foo/foo.c");
-}
-
-void test_status_ignore__deeper(void)
-{
- const char *test_files[] = {
- "empty_standard_repo/foo.data",
- "empty_standard_repo/bar.data",
- "empty_standard_repo/dont_ignore/foo.data",
- "empty_standard_repo/dont_ignore/bar.data",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile("empty_standard_repo/.gitignore",
- "*.data\n"
- "!dont_ignore/*.data\n");
-
- assert_is_ignored("foo.data");
- assert_is_ignored("bar.data");
-
- refute_is_ignored("dont_ignore/foo.data");
- refute_is_ignored("dont_ignore/bar.data");
-}
-
-void test_status_ignore__unignored_dir_with_ignored_contents(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/dir/a.test",
- "empty_standard_repo/dir/subdir/a.test",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "*.test\n"
- "!dir/*\n");
-
- refute_is_ignored("dir/a.test");
- assert_is_ignored("dir/subdir/a.test");
-}
-
-void test_status_ignore__unignored_subdirs(void)
-{
- static const char *test_files[] = {
- "empty_standard_repo/dir/a.test",
- "empty_standard_repo/dir/subdir/a.test",
- NULL
- };
-
- make_test_data("empty_standard_repo", test_files);
- cl_git_mkfile(
- "empty_standard_repo/.gitignore",
- "dir/*\n"
- "!dir/*/\n");
-
- assert_is_ignored("dir/a.test");
- refute_is_ignored("dir/subdir/a.test");
-}
const char** expected_paths;
int expected_entry_count;
const char *file;
+ const char *func;
int line;
bool debug;
} status_entry_counts;
(counts).expected_statuses = (statuses); \
(counts).expected_paths = (paths); \
(counts).file = __FILE__; \
+ (counts).func = __func__; \
(counts).line = __LINE__; \
} while (0)
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "status_helpers.h"
#include "../submodule/submodule_helpers.h"
int idx = counts->entry_count++;
clar__assert_equal(
- counts->file, counts->line,
+ counts->file, counts->func, counts->line,
"Status path mismatch", 1,
"%s", counts->expected_paths[idx], p);
clar__assert_equal(
- counts->file, counts->line,
+ counts->file, counts->func, counts->line,
"Status code mismatch", 1,
"%o", counts->expected_statuses[idx], s);
#include "clar_libgit2.h"
-#include "fileops.h"
+#include "futils.h"
#include "ignore.h"
#include "status_data.h"
#include "posix.h"
void test_status_worktree__long_filenames(void)
{
- char path[260*4+1];
+ char path[260*4+1] = {0};
const char *expected_paths[] = {path};
const unsigned int expected_statuses[] = {GIT_STATUS_WT_NEW};
#include "clar_libgit2.h"
#include "git2/sys/repository.h"
-#include "fileops.h"
+#include "futils.h"
#include "ignore.h"
#include "status_helpers.h"
#include "posix.h"
-#undef GIT_DEPRECATE_HARD
-
#include "clar_libgit2.h"
#include "git2/sys/stream.h"
#include "streams/tls.h"
#include "streams/socket.h"
#include "stream.h"
-static git_stream test_stream;
-static int ctor_called;
-
void test_stream_deprecated__cleanup(void)
{
cl_git_pass(git_stream_register(GIT_STREAM_TLS | GIT_STREAM_STANDARD, NULL));
}
+#ifndef GIT_DEPRECATE_HARD
+static git_stream test_stream;
+static int ctor_called;
+
static int test_stream_init(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(host);
return 0;
}
+#endif
void test_stream_deprecated__register_tls(void)
{
+#ifndef GIT_DEPRECATE_HARD
git_stream *stream;
int error;
cl_assert(&test_stream != stream);
git_stream_free(stream);
+#endif
}
#include "path.h"
#include "submodule_helpers.h"
#include "config/config_helpers.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
+#include "git2/sys/commit.h"
static git_repository *g_repo = NULL;
static const char *valid_blob_id = "fa49b077972391ad58037050f2a75f74e3671e92";
/* make sure we don't default to origin - rename origin -> test_remote */
cl_git_pass(git_remote_rename(&problems, g_repo, "origin", "test_remote"));
cl_assert_equal_i(0, problems.count);
- git_strarray_free(&problems);
+ git_strarray_dispose(&problems);
cl_git_fail(git_remote_lookup(&remote, g_repo, "origin"));
cl_git_pass(
git_submodule_free(sm);
git_buf_dispose(&name);
}
+
+void test_submodule_add__submodule_clone(void)
+{
+ git_oid tree_id, commit_id;
+ git_signature *sig;
+ git_submodule *sm;
+ git_index *index;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ /* Create the submodule structure, clone into it and finalize */
+ cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "testrepo-add", true));
+ cl_git_pass(git_submodule_clone(NULL, sm, NULL));
+ cl_git_pass(git_submodule_add_finalize(sm));
+
+ /* Create the submodule commit */
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_index_write_tree(&tree_id, index));
+ cl_git_pass(git_signature_now(&sig, "Submoduler", "submoduler@local"));
+ cl_git_pass(git_commit_create_from_ids(&commit_id, g_repo, "HEAD", sig, sig, NULL, "A submodule\n",
+ &tree_id, 0, NULL));
+
+ assert_submodule_exists(g_repo, "testrepo-add");
+
+ git_signature_free(sig);
+ git_submodule_free(sm);
+ git_index_free(index);
+}
+
+void test_submodule_add__submodule_clone_into_nonempty_dir_succeeds(void)
+{
+ git_submodule *sm;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ cl_git_pass(p_mkdir("empty_standard_repo/sm", 0777));
+ cl_git_mkfile("empty_standard_repo/sm/foobar", "");
+
+ /* Create the submodule structure, clone into it and finalize */
+ cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "sm", true));
+ cl_git_pass(git_submodule_clone(NULL, sm, NULL));
+ cl_git_pass(git_submodule_add_finalize(sm));
+
+ cl_assert(git_path_exists("empty_standard_repo/sm/foobar"));
+
+ assert_submodule_exists(g_repo, "sm");
+
+ git_submodule_free(sm);
+}
+
+void test_submodule_add__submodule_clone_twice_fails(void)
+{
+ git_submodule *sm;
+
+ g_repo = cl_git_sandbox_init("empty_standard_repo");
+
+ /* Create the submodule structure, clone into it and finalize */
+ cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "sm", true));
+ cl_git_pass(git_submodule_clone(NULL, sm, NULL));
+ cl_git_pass(git_submodule_add_finalize(sm));
+
+ cl_git_fail(git_submodule_clone(NULL, sm, NULL));
+
+ git_submodule_free(sm);
+}
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
static git_repository *g_repo = NULL;
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo = NULL;
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
-#include "fileops.h"
+#include "futils.h"
#include "repository.h"
static git_repository *g_repo = NULL;
#include "submodule_helpers.h"
#include "git2/sys/repository.h"
#include "repository.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo = NULL;
cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm));
git_submodule_free(sm);
}
+
+void test_submodule_modify__set_relative_url(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_repository *repo;
+ git_submodule *sm;
+
+ cl_git_pass(git_submodule_set_url(g_repo, SM1, "../relative-url"));
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, SM1));
+ cl_git_pass(git_submodule_sync(sm));
+ cl_git_pass(git_submodule_open(&repo, sm));
+
+ cl_git_pass(git_buf_joinpath(&path, clar_sandbox_path(), "relative-url"));
+
+ assert_config_entry_value(g_repo, "submodule."SM1".url", path.ptr);
+ assert_config_entry_value(repo, "remote.origin.url", path.ptr);
+
+ git_repository_free(repo);
+ git_submodule_free(sm);
+ git_buf_dispose(&path);
+}
#include "clar_libgit2.h"
#include "posix.h"
-#include "fileops.h"
+#include "futils.h"
void test_submodule_nosubs__cleanup(void)
{
#include "path.h"
#include "submodule_helpers.h"
#include "config/config_helpers.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo = NULL;
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
-#include "fileops.h"
+#include "futils.h"
#include "iterator.h"
static git_repository *g_repo = NULL;
void assert__submodule_exists(
git_repository *repo, const char *name,
- const char *msg, const char *file, int line)
+ const char *msg, const char *file, const char *func, int line)
{
git_submodule *sm;
int error = git_submodule_lookup(&sm, repo, name);
if (error)
- cl_git_report_failure(error, 0, file, line, msg);
- cl_assert_at_line(sm != NULL, file, line);
+ cl_git_report_failure(error, 0, file, func, line, msg);
+ cl_assert_at_line(sm != NULL, file, func, line);
git_submodule_free(sm);
}
void refute__submodule_exists(
git_repository *repo, const char *name, int expected_error,
- const char *msg, const char *file, int line)
+ const char *msg, const char *file, const char *func, int line)
{
clar__assert_equal(
- file, line, msg, 1, "%i",
+ file, func, line, msg, 1, "%i",
expected_error, (int)(git_submodule_lookup(NULL, repo, name)));
}
extern unsigned int get_submodule_status(git_repository *, const char *);
-extern void assert__submodule_exists(
- git_repository *, const char *, const char *, const char *, int);
+extern void assert__submodule_exists(git_repository *, const char *,
+ const char *, const char *, const char *, int);
#define assert_submodule_exists(repo,name) \
- assert__submodule_exists(repo, name, "git_submodule_lookup(" #name ") failed", __FILE__, __LINE__)
+ assert__submodule_exists(repo, name, "git_submodule_lookup(" #name ") failed", __FILE__, __func__, __LINE__)
-extern void refute__submodule_exists(
- git_repository *, const char *, int err, const char *, const char *, int);
+extern void refute__submodule_exists(git_repository *, const char *,
+ int err, const char *, const char *, const char *, int);
#define refute_submodule_exists(repo,name,code) \
- refute__submodule_exists(repo, name, code, "expected git_submodule_lookup(" #name ") to fail with error " #code, __FILE__, __LINE__)
+ refute__submodule_exists(repo, name, code, "expected git_submodule_lookup(" #name ") to fail with error " #code, __FILE__, __func__, __LINE__)
extern void dump_submodules(git_repository *repo);
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
-#include "fileops.h"
+#include "futils.h"
static git_repository *g_repo = NULL;
*aux_id = aux_counter++;
}
-static void aux_cb_lookup__1(unsigned int aux_id, char *aux_msg, unsigned int aux_msg_len)
+static void aux_cb_lookup__1(unsigned int aux_id, char *aux_msg, size_t aux_msg_len)
{
p_snprintf(aux_msg, aux_msg_len, "\tQQ%08x\n", aux_id);
}
#include "git2/clone.h"
#include "clone.h"
#include "buffer.h"
-#include "fileops.h"
+#include "futils.h"
static git_buf path = GIT_BUF_INIT;
cl_git_pass(git_worktree_list(&wts, g_repo));
cl_assert_equal_i(wts.count, 0);
- git_strarray_free(&wts);
+ git_strarray_dispose(&wts);
}
void test_worktree_bare__add(void)
cl_assert_equal_i(0, git_repository_is_bare(wtrepo));
cl_assert_equal_i(1, git_repository_is_worktree(wtrepo));
- git_strarray_free(&wts);
+ git_strarray_dispose(&wts);
git_worktree_free(wt);
git_repository_free(wtrepo);
}
}
exit:
- git_strarray_free(&refs);
- git_strarray_free(&wtrefs);
+ git_strarray_dispose(&refs);
+ git_strarray_dispose(&wtrefs);
cl_git_pass(error);
}
cl_git_pass(git_branch_lookup(&branch, fixture.repo,
"testrepo-worktree", GIT_BRANCH_LOCAL));
cl_git_pass(git_reference_rename(&renamed, branch, "refs/heads/renamed", 0, NULL));
- cl_git_pass(git_repository_head(&head, fixture.worktree));
+
+ cl_git_pass(git_reference_lookup(&head, fixture.worktree, GIT_HEAD_FILE));
+ cl_assert_equal_i(git_reference_type(head), GIT_REFERENCE_SYMBOLIC);
+ cl_assert_equal_s(git_reference_symbolic_target(head), "refs/heads/renamed");
git_reference_free(head);
git_reference_free(branch);
cl_assert(git_repository_head_detached(fixture.worktree));
cl_assert(git_repository_head_detached_for_worktree(fixture.repo, "testrepo-worktree"));
- cl_git_fail(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
+ cl_git_pass(git_repository_head_for_worktree(&head, fixture.repo, "testrepo-worktree"));
+
+ cl_assert_equal_oid(&ref->target.oid, &head->target.oid);
git_reference_free(ref);
+ git_reference_free(head);
}
void test_worktree_repository__head_detached_fails_for_invalid_worktree(void)
cl_assert_equal_i(wts.count, 1);
cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
- git_strarray_free(&wts);
+ git_strarray_dispose(&wts);
}
void test_worktree_worktree__list_with_invalid_worktree_dirs(void)
};
git_buf path = GIT_BUF_INIT;
git_strarray wts;
- unsigned i, j, len;
+ size_t i, j, len;
cl_git_pass(git_buf_printf(&path, "%s/worktrees/invalid",
fixture.repo->commondir));
cl_git_pass(git_worktree_list(&wts, fixture.worktree));
cl_assert_equal_i(wts.count, 1);
cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
- git_strarray_free(&wts);
+ git_strarray_dispose(&wts);
for (j = 0; j < ARRAY_SIZE(filesets[i]); j++) {
git_buf_truncate(&path, len);
cl_assert_equal_i(wts.count, 1);
cl_assert_equal_s(wts.strings[0], "testrepo-worktree");
- git_strarray_free(&wts);
+ git_strarray_dispose(&wts);
}
void test_worktree_worktree__list_without_worktrees(void)
cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree"));
cl_assert_equal_s(git_worktree_name(wt), "testrepo-worktree");
-
+
git_worktree_free(wt);
}
git_worktree_free(wt);
}
-static int read_head_ref(git_repository *repo, const char *path, void *payload)
+static int foreach_worktree_cb(git_repository *worktree, void *payload)
{
- git_vector *refs = (git_vector *) payload;
- git_reference *head;
-
- GIT_UNUSED(repo);
+ int *counter = (int *)payload;
- cl_git_pass(git_reference__read_head(&head, repo, path));
+ switch (*counter) {
+ case 0:
+ cl_assert_equal_s(git_repository_path(fixture.repo),
+ git_repository_path(worktree));
+ cl_assert(!git_repository_is_worktree(worktree));
+ break;
+ case 1:
+ cl_assert_equal_s(git_repository_path(fixture.worktree),
+ git_repository_path(worktree));
+ cl_assert(git_repository_is_worktree(worktree));
+ break;
+ default:
+ cl_fail("more worktrees found than expected");
+ }
- git_vector_insert(refs, head);
+ (*counter)++;
return 0;
}
-void test_worktree_worktree__foreach_head_gives_same_results_in_wt_and_repo(void)
+void test_worktree_worktree__foreach_worktree_lists_all_worktrees(void)
{
- git_vector repo_refs = GIT_VECTOR_INIT, worktree_refs = GIT_VECTOR_INIT;
- git_reference *heads[2];
- size_t i;
-
- cl_git_pass(git_reference_lookup(&heads[0], fixture.repo, GIT_HEAD_FILE));
- cl_git_pass(git_reference_lookup(&heads[1], fixture.worktree, GIT_HEAD_FILE));
-
- cl_git_pass(git_repository_foreach_head(fixture.repo, read_head_ref, &repo_refs));
- cl_git_pass(git_repository_foreach_head(fixture.worktree, read_head_ref, &worktree_refs));
-
- cl_assert_equal_i(repo_refs.length, ARRAY_SIZE(heads));
- cl_assert_equal_i(worktree_refs.length, ARRAY_SIZE(heads));
-
- for (i = 0; i < ARRAY_SIZE(heads); i++) {
- cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name);
- cl_assert_equal_s(heads[i]->name, ((git_reference *) repo_refs.contents[i])->name);
- cl_assert_equal_s(heads[i]->name, ((git_reference *) worktree_refs.contents[i])->name);
-
- git_reference_free(heads[i]);
- git_reference_free(repo_refs.contents[i]);
- git_reference_free(worktree_refs.contents[i]);
- }
-
- git_vector_free(&repo_refs);
- git_vector_free(&worktree_refs);
+ int counter = 0;
+ cl_git_pass(git_repository_foreach_worktree(fixture.repo, foreach_worktree_cb, &counter));
}