pax_global_header00006660000000000000000000000064151143274060014515gustar00rootroot0000000000000052 comment=04e937470d3679cc163df85d82d5b6d2e3e71128 commons-text-rel-commons-text-1.15.0/000077500000000000000000000000001511432740600174515ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/.asf.yaml000066400000000000000000000026171511432740600211720ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. github: description: "Apache Commons Text" homepage: https://commons.apache.org/text/ notifications: commits: commits@commons.apache.org issues: issues@commons.apache.org pullrequests: issues@commons.apache.org jira_options: link label jobs: notifications@commons.apache.org # commits_bot_dependabot: dependabot@commons.apache.org issues_bot_dependabot: dependabot@commons.apache.org pullrequests_bot_dependabot: dependabot@commons.apache.org issues_bot_codecov-commenter: notifications@commons.apache.org pullrequests_bot_codecov-commenter: notifications@commons.apache.org commons-text-rel-commons-text-1.15.0/.github/000077500000000000000000000000001511432740600210115ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/.github/GH-ROBOTS.txt000066400000000000000000000016341511432740600230620ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Keeps on creating FUD PRs in test code # Does not follow Apache disclosure policies User-agent: JLLeitschuh/security-research Disallow: * commons-text-rel-commons-text-1.15.0/.github/dependabot.yml000066400000000000000000000017451511432740600236500ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version: 2 updates: - package-ecosystem: "maven" directory: "/" schedule: interval: "quarterly" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "quarterly" commons-text-rel-commons-text-1.15.0/.github/pull_request_template.md000066400000000000000000000034561511432740600257620ustar00rootroot00000000000000 Thanks for your contribution to [Apache Commons](https://commons.apache.org/)! Your help is appreciated! Before you push a pull request, review this list: - [ ] Read the [contribution guidelines](CONTRIBUTING.md) for this project. - [ ] Read the [ASF Generative Tooling Guidance](https://www.apache.org/legal/generative-tooling.html) if you use Artificial Intelligence (AI). - [ ] I used AI to create any part of, or all of, this pull request. - [ ] Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself. - [ ] Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best practice. - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. - [ ] Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process. commons-text-rel-commons-text-1.15.0/.github/workflows/000077500000000000000000000000001511432740600230465ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/.github/workflows/codeql-analysis.yml000066400000000000000000000061521511432740600266650ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '33 9 * * 4' permissions: contents: read jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'java' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 # â„¹ï¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # âœï¸ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 commons-text-rel-commons-text-1.15.0/.github/workflows/dependency-review.yml000066400000000000000000000022351511432740600272100ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. name: 'Dependency Review' on: [pull_request] permissions: contents: read jobs: dependency-review: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: 'Dependency Review PR' uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 commons-text-rel-commons-text-1.15.0/.github/workflows/maven.yml000066400000000000000000000031401511432740600246750ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. name: Java CI on: [push, pull_request] permissions: contents: read jobs: build: runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} strategy: matrix: java: [ 8, 11, 17, 21, 25 ] experimental: [false] include: - java: 26-ea experimental: true steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: 'temurin' java-version: ${{ matrix.java }} cache: 'maven' - name: Build with Maven run: mvn --errors --show-version --batch-mode --no-transfer-progress -Dpolyglot.engine.WarnInterpreterOnly=false commons-text-rel-commons-text-1.15.0/.github/workflows/scorecards-analysis.yml000066400000000000000000000047441511432740600275530ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache license, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the license for the specific language governing permissions and # limitations under the license. name: "Scorecards supply-chain security" on: branch_protection_rule: schedule: - cron: "30 1 * * 6" # Weekly on Saturdays push: branches: [ "master" ] permissions: read-all jobs: analysis: name: "Scorecards analysis" runs-on: ubuntu-latest permissions: # Needed to upload the results to the code-scanning dashboard. security-events: write actions: read id-token: write # This is required for requesting the JWT contents: read # This is required for actions/checkout steps: - name: "Checkout code" uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # 2.4.3 with: results_file: results.sarif results_format: sarif # A read-only PAT token, which is sufficient for the action to function. # The relevant discussion: https://github.com/ossf/scorecard-action/issues/188 repo_token: ${{ secrets.GITHUB_TOKEN }} # Publish the results for public repositories to enable scorecard badges. # For more details: https://github.com/ossf/scorecard-action#publishing-results publish_results: true - name: "Upload artifact" uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # 5.0.0 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 with: sarif_file: results.sarif commons-text-rel-commons-text-1.15.0/.gitignore000066400000000000000000000003371511432740600214440ustar00rootroot00000000000000# Maven build files target *.log maven-eclipse.xml build.properties site-content *~ # IntelliJ IDEA files .idea .iws *.iml *.ipr # Eclipse files .settings .classpath .project .externalToolBuilders /.checkstyle /.DS_Store commons-text-rel-commons-text-1.15.0/CODE_OF_CONDUCT.md000066400000000000000000000016421511432740600222530ustar00rootroot00000000000000 The Apache code of conduct page is [https://www.apache.org/foundation/policies/conduct.html](https://www.apache.org/foundation/policies/conduct.html). commons-text-rel-commons-text-1.15.0/CONTRIBUTING.md000066400000000000000000000156041511432740600217100ustar00rootroot00000000000000 Contributing to Apache Commons Text ====================== Have you found a bug or have an idea for a cool new feature? Contributing code is a great way to give something back to the open-source community. Before you dig right into the code, we need contributors to follow a few guidelines to have a chance of keeping on top of things. Getting Started --------------- + Make sure you have a [JIRA account](https://issues.apache.org/jira/). + Make sure you have a [GitHub account](https://github.com/signup/free). This is not essential, but makes providing patches much easier. + If you're planning to implement a new feature it makes sense to discuss your changes on the [dev list](https://commons.apache.org/mail-lists.html) first. This way you can make sure you're not wasting your time on something that isn't considered to be in Apache Commons Text's scope. + Submit a [Jira Ticket][jira] for your issue, assuming one does not already exist. + Clearly describe the issue including steps to reproduce when it is a bug. + Make sure you fill in the earliest version that you know has the issue. + Find the corresponding [repository on GitHub](https://github.com/apache/?query=commons-), [fork](https://help.github.com/articles/fork-a-repo/) and check out your forked repository. If you don't have a GitHub account, you can still clone the Commons repository. Making Changes -------------- + Create a _topic branch_ for your isolated work. * Usually you should base your branch from the `master` branch. * A good topic branch name can be the JIRA bug ID plus a keyword, e.g. `TEXT-123-InputStream`. * If you have submitted multiple JIRA issues, try to maintain separate branches and pull requests. + Make commits of logical units. * Make sure your commit messages are meaningful and in the proper format. Your commit message should contain the key of the JIRA issue. * For example, `[TEXT-123] Close input stream sooner` + Respect the original code style: + Only use spaces for indentation; you can check for unnecessary whitespace with `git diff` before committing. + Create minimal diffs - disable _On Save_ actions like _Reformat Source Code_ or _Organize Imports_. If you feel the source code should be reformatted create a separate PR for this change first. + Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible but is a best practice. Unit tests are typically in the `src/test/java` directory. + Run a successful build using the default [Maven](https://maven.apache.org/) goal with `mvn`; that's `mvn` on the command line by itself. + Write a pull request description that is detailed enough to understand what the pull request does, how, and why. + Each commit in the pull request should have a meaningful subject line and body. Note that commits might be squashed by a maintainer on merge. Making Trivial Changes ---------------------- The JIRA tickets are used to generate the changelog for the next release. For changes of a trivial nature to comments and documentation, it is not always necessary to create a new ticket in JIRA. In this case, it is appropriate to start the first line of a commit with '[doc]' or '[javadoc]' instead of a ticket number. Submitting Changes ------------------ + Sign and submit the Apache [Contributor License Agreement][cla] if you haven't already. * Note that small patches & typical bug fixes do not require a CLA as clause 5 of the [Apache License](https://www.apache.org/licenses/LICENSE-2.0.html#contributions) covers them. + Push your changes to a topic branch in your fork of the repository. + Submit a _Pull Request_ to the corresponding repository in the `apache` organization. * Verify _Files Changed_ shows only your intended changes and does not include additional files like `target/*.class` + Update your JIRA ticket and include a link to the pull request in the ticket. If you prefer to not use GitHub, then you can instead use `git format-patch` (or `svn diff`) and attach the patch file to the JIRA issue. Additional Resources -------------------- + [Contributing patches](https://commons.apache.org/patches.html) + [Apache Commons Text JIRA project page][jira] + [Contributor License Agreement][cla] + [General GitHub documentation](https://help.github.com/) + [GitHub pull request documentation](https://help.github.com/articles/creating-a-pull-request/) + [Apache Commons Twitter Account](https://twitter.com/ApacheCommons) [cla]:https://www.apache.org/licenses/#clas [jira]:https://issues.apache.org/jira/browse/TEXT commons-text-rel-commons-text-1.15.0/LICENSE.txt000066400000000000000000000261371511432740600213050ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. commons-text-rel-commons-text-1.15.0/NOTICE.txt000066400000000000000000000002561511432740600211760ustar00rootroot00000000000000Apache Commons Text Copyright 2014-2025 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (https://www.apache.org/). commons-text-rel-commons-text-1.15.0/README.md000066400000000000000000000147271511432740600207430ustar00rootroot00000000000000 Apache Commons Text =================== [![Java CI](https://github.com/apache/commons-text/actions/workflows/maven.yml/badge.svg)](https://github.com/apache/commons-text/actions/workflows/maven.yml) [![Maven Central](https://img.shields.io/maven-central/v/org.apache.commons/commons-text?label=Maven%20Central)](https://search.maven.org/artifact/org.apache.commons/commons-text) [![Javadocs](https://javadoc.io/badge/org.apache.commons/commons-text/1.15.0.svg)](https://javadoc.io/doc/org.apache.commons/commons-text/1.15.0) [![CodeQL](https://github.com/apache/commons-text/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/apache/commons-text/actions/workflows/codeql-analysis.yml) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/apache/commons-text/badge)](https://api.securityscorecards.dev/projects/github.com/apache/commons-text) Apache Commons Text is a set of utility functions and reusable components for processing and manipulating text in a Java environment. Documentation ------------- More information can be found on the [Apache Commons Text homepage](https://commons.apache.org/proper/commons-text). The [Javadoc](https://commons.apache.org/proper/commons-text/apidocs) can be browsed. Questions related to the usage of Apache Commons Text should be posted to the [user mailing list](https://commons.apache.org/mail-lists.html). Getting the latest release -------------------------- You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-text/download_text.cgi). Alternatively, you can pull it from the central Maven repositories: ```xml org.apache.commons commons-text 1.15.0 ``` Building -------- Building requires a Java JDK and [Apache Maven](https://maven.apache.org/). The required Java version is found in the `pom.xml` as the `maven.compiler.source` property. From a command shell, run `mvn` without arguments to invoke the default Maven goal to run all tests and checks. Contributing ------------ We accept Pull Requests via GitHub. The [developer mailing list](https://commons.apache.org/mail-lists.html) is the main channel of communication for contributors. There are some guidelines which will make applying PRs easier for us: + No tabs! Please use spaces for indentation. + Respect the existing code style for each file. + Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change. + Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running `mvn`. + Before you push a PR, run `mvn` (without arguments). This runs the default goal which contains all build checks. + To see the code coverage report, regardless of coverage failures, run `mvn clean site -Dcommons.jacoco.haltOnFailure=false -Pjacoco` If you plan to contribute on a regular basis, please consider filing a [contributor license agreement](https://www.apache.org/licenses/#clas). You can learn more about contributing via GitHub in our [contribution guidelines](CONTRIBUTING.md). License ------- This code is licensed under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0). See the `NOTICE.txt` file for required notices and attributions. Donating -------- You like Apache Commons Text? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support development. Additional Resources -------------------- + [Apache Commons Homepage](https://commons.apache.org/) + [Apache Issue Tracker (JIRA)](https://issues.apache.org/jira/browse/TEXT) + [Apache Commons Slack Channel](https://the-asf.slack.com/archives/C60NVB8AD) + [Apache Commons Twitter Account](https://twitter.com/ApacheCommons) Apache Commons Components ------------------------- Please see the [list of components](https://commons.apache.org/components.html) commons-text-rel-commons-text-1.15.0/RELEASE-NOTES.txt000066400000000000000000001435171511432740600221730ustar00rootroot00000000000000 Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Apache Commons Text 1.15.0 Release Notes ---------------------------------------- The Apache Commons Text team is pleased to announce the release of Apache Commons Text 1.15.0. Apache Commons Text is a set of utility functions and reusable components for processing and manipulating text in a Java environment. Release 1.15.0. This is a feature and maintenance release. Java 8 or later is required. New features ------------ * Add experimental CycloneDX VEX file #683. Thanks to Piotr P. Karwasz, Gary Gregory. * TEXT-235: Add Damerau-Levenshtein distance #687. Thanks to LorgeN, Gary Gregory. * Add unit tests to increase coverage #719. Thanks to Michael Hausegger, Gary Gregory. * Add new test for CharSequenceTranslator#with() #725. Thanks to Michael Hausegger, Gary Gregory. * Add tests and assertions to org.apache.commons.text.similarity to get to 100% code coverage #727, #728. Thanks to Michael Hausegger. Fixed Bugs ---------- * Fix exception message typo in XmlStringLookup.XmlStringLookup(Map, Path...). Thanks to Gary Gregory. * TEXT-236: Inserting at the end of a TextStringBuilder throws a StringIndexOutOfBoundsException. Thanks to Pierre Post, Sumit Bera, Alex Herbert, Gary Gregory. * Fix TextStringBuilderTest.testAppendToCharBuffer() to use proper argument type #724. Thanks to Michael Hausegger. * Fix Apache RAT plugin console warnings. Thanks to Gary Gregory. * Fix site XML to use version 2.0.0 XML schema. Thanks to Gary Gregory. * Removed unreachable threshold verification code in src/main/java/org/apache/commons/text/similarity #730. Thanks to Michael Hausegger. * Enable secure processing for the XML parser in XmlStringLookup in case the underlying JAXP implementation doesn't #729. Thanks to 김민재 (minjas0507), Gary Gregory, Piotr Karwasz. Changes ------- * Bump org.apache.commons:commons-parent from 85 to 93 #704, #723, #726. Thanks to Gary Gregory. * Bump commons.bytebuddy.version from 1.17.6 to 1.18.2 #696, #722. Thanks to Gary Gregory. * Bump graalvm.version from 24.2.2 to 25.0.1 #703, #716. Thanks to Gary Gregory, Dependabot. * Bump org.apache.commons:commons-lang3 from 3.18.0 to 3.20.0. Thanks to Gary Gregory. * Bump commons-io:commons-io from 2.20.0 to 2.21.0. Thanks to Gary Gregory. Historical list of changes: https://commons.apache.org/proper/commons-text/changes.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ----------------------------------------------------------------------------- Apache Commons Text 1.14.0 Release Notes ---------------------------------------- The Apache Commons Text team is pleased to announce the release of Apache Commons Text 1.14.0. Apache Commons Text is a set of utility functions and reusable components for processing and manipulating text in a Java environment. Release 1.14.0. Requires Java 8 or above. New features ------------ * Interface StringLookup now extends UnaryOperator. Thanks to Gary Gregory. * Interface TextRandomProvider extends IntUnaryOperator. Thanks to Gary Gregory. * Add RandomStringGenerator.Builder.usingRandom(IntUnaryOperator). Thanks to Gary Gregory. * Add PMD check to default Maven goal. Thanks to Gary Gregory. * Add org.apache.commons.text.RandomStringGenerator.Builder.setAccumulate(boolean). Thanks to Gary Gregory. Fixed Bugs ---------- * Fix PMD UnnecessaryFullyQualifiedName in StringLookupFactory. Thanks to Gary Gregory. * Fix PMD UnnecessaryFullyQualifiedName in DefaultStringLookupsHolder. Thanks to Gary Gregory. * Fix PMD UnnecessaryFullyQualifiedName in PropertiesStringLookup. Thanks to Gary Gregory. * Fix PMD UnnecessaryFullyQualifiedName in JavaPlatformStringLookup. Thanks to Gary Gregory. * Fix PMD UnnecessaryFullyQualifiedName in StringSubstitutor. Thanks to Gary Gregory. * Fix PMD UnnecessaryFullyQualifiedName in StrSubstitutor. Thanks to Gary Gregory. * Fix PMD UnnecessaryFullyQualifiedName in AlphabetConverter. Thanks to Gary Gregory. * Fix PMD AvoidBranchingStatementAsLastInLoop in TextStringBuilder. Thanks to Gary Gregory. * Fix PMD AvoidBranchingStatementAsLastInLoop in StrBuilder. Thanks to Gary Gregory. * org.apache.commons.text.translate.LookupTranslator.LookupTranslator(Map CharSequence>) now throws NullPointerException instead of java.security.InvalidParameterException. Thanks to Gary Gregory. Changes ------- * Bump org.apache.commons:commons-parent from 81 to 85 #668. Thanks to Dependabot, Gary Gregory. * Bump commons-io:commons-io from 2.18.0 to 2.20.0. Thanks to Gary Gregory. * Bump graalvm.version from 24.2.0 to 24.2.2 #665, #681. Thanks to Dependabot, Gary Gregory. * Bump commons.bytebuddy.version from 1.17.5 to 1.17.6 (#677). Thanks to Dependabot. * Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0 #680. Thanks to Dependabot. Historical list of changes: https://commons.apache.org/proper/commons-text/changes.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ----------------------------------------------------------------------------- Apache Commons Text 1.13.1 Release Notes ---------------------------------------- This document contains the release notes for the 1.13.1 version of Apache Commons Text. Apache Commons Text is a set of utility functions and reusable components for processing and manipulating text in a Java environment. Release 1.13.1. Requires Java 8 or above. Fixed Bugs ---------- * Remove -nouses directive from maven-bundle-plugin. OSGi package imports now state 'uses' definitions for package imports, this doesn't affect JPMS (from org.apache.commons:commons-parent:80). Thanks to Gary Gregory. * Deprecate EntityArrays.EntityArrays(). Thanks to Gary Gregory. * StringLookupFactory.DefaultStringLookupsHolder.createDefaultStringLookups() maps DefaultStringLookup.LOCAL_HOST twice instead of once for LOCAL_HOST and LOOPBACK_ADDRESS. Thanks to Gary Gregory. Changes ------- * Bump org.apache.commons:commons-parent from 79 to 81. Thanks to Gary Gregory. * Bump commons.bytebuddy.version from 1.16.1 to 1.17.5 #643, #659, #660. Thanks to Gary Gregory, Dependabot. * Bump graalvm.version from 24.1.2 to 24.2.0 #653. Thanks to Gary Gregory, Dependabot. Historical list of changes: https://commons.apache.org/proper/commons-text/changes.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ----------------------------------------------------------------------------- Apache Commons Text Version 1.13.0 Release Notes ------------------------------------------------ This document contains the release notes for the 1.13.0 version of Apache Commons Text. Apache Commons Text is a set of utility functions and reusable components for processing and manipulating text in a Java environment. Release 1.13.0. Requires Java 8 or above. New features ------------ * Add StringLookupFactory.loopbackAddressStringLookup(). Thanks to Gary Gregory. * Add StringLookupFactory.KEY_LOOPBACK_ADDRESS. Thanks to Gary Gregory. * Add DefaultStringLookup.LOOPBACK_ADDRESS. Thanks to Gary Gregory. * Add richer inputs in package org.apache.commons.text.similarity with SimilarityInput. Thanks to Gary Gregory. * Add HammingDistance.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. * Add JaccardDistance.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. * Add JaccardSimilarity.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. * Add JaroWinklerDistance.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. * Add JaroWinklerSimilarity.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. * Add LevenshteinDetailedDistance.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. * Add LevenshteinDistance.apply(SimilarityInput, SimilarityInput). Thanks to Gary Gregory. Fixed Bugs ---------- * Fix build on Java 22. Thanks to Gary Gregory. * Fix build on Java 23-ea. Thanks to Gary Gregory. * Make package-private constructor private: StrLookup.MapStrLookup.MapStrLookup(Map). Thanks to Gary Gregory. * Make package-private constructor private: StrLookup.SystemPropertiesStrLookup.SystemPropertiesStrLookup(). Thanks to Gary Gregory. * Make package-private class private and final: MapStrLookup. Thanks to Gary Gregory. * Make package-private class private: StrMatcher.CharMatcher. Thanks to Gary Gregory. * Make package-private class private: StrMatcher.CharSetMatcher. Thanks to Gary Gregory. * Make package-private class private: StrMatcher.NoMatcher. Thanks to Gary Gregory. * Make package-private class private: StrMatcher.StringMatcher. Thanks to Gary Gregory. * Make package-private class private: StrMatcher.TrimMatcher. Thanks to Gary Gregory. * Make package-private class private and final: IntersectionSimilarity.BagCount. Thanks to Gary Gregory. * Make package-private class private and final: IntersectionSimilarity.TinyCount. Thanks to Gary Gregory. * Deprecate LevenshteinDistance.LevenshteinDistance() in favor of LevenshteinDistance.getDefaultInstance(). Thanks to Gary Gregory. * Deprecate LevenshteinDetailedDistance.LevenshteinDetailedDistance() in favor of LevenshteinDetailedDistance.getDefaultInstance(). Thanks to Gary Gregory. * TEXT-234: Improve StrBuilder documentation for new line text. Thanks to Gary Gregory. * TEXT-234: Improve TextStringBuilder documentation for new line text #547. Thanks to TobiasKiecker. * TEXT-233: Required OSGi Import-Package version numbers in MANIFEST.MF #627. Thanks to belpk. Changes ------- * Bump org.apache.commons:commons-parent from 69 to 78 #542, #557, #571, #581, #584, #593, #600, #603, #614. Thanks to Dependabot. * Bump commons.bytebuddy.version from 1.14.13 to 1.15.10 #538, #548, #553, #565, #579, #582, #585, #596, #597, #604, #612, #620, #623, #625. Thanks to Gary Gregory. * Bump SpotBugs from 4.8.3 to 4.8.5. Thanks to Gary Gregory. * Bump org.assertj:assertj-core from 3.25.3 to 3.26.3 #554, #566. Thanks to Dependabot. * Bump org.codehaus.mojo:taglist-maven-plugin from 3.0.0 to 3.2.1 #564, #611. Thanks to Dependabot. * Bump org.apache.commons:commons-rng-simple from 1.5 to 1.6 #568. Thanks to Dependabot, Gary Gregory. * Bump org.apache.commons:commons-lang3 from 3.14.0 to 3.17.0 #569, #575, #586. Thanks to Dependabot, Gary Gregory. * Bump commons-io:commons-io from 2.16.1 to 2.18.0 #594, #628. Thanks to Dependabot, Gary Gregory. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ----------------------------------------------------------------------------- Apache Commons Text Version 1.12.0 Release Notes ------------------------------------------------ This document contains the release notes for the 1.12.0 version of Apache Commons Text. Apache Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. Release 1.12.0. Requires Java 8 or above. New features ------------ * Add StringLookupFactory.fileStringLookup(Path...) and deprecated fileStringLookup(). Thanks to Gary Gregory. * Add StringLookupFactory.propertiesStringLookup(Path...) and deprecated propertiesStringLookup(). Thanks to Gary Gregory. * Add StringLookupFactory.xmlStringLookup(Map, Path...) and deprecated xmlStringLookup() and xmlStringLookup(Map). Thanks to Gary Gregory. * Add StringLookupFactory.builder() for fencing Path resolution of the file, properties and XML lookups. Thanks to Gary Gregory. * Add DoubleFormat.Builder.get() as Builder now implements Supplier. Thanks to Gary Gregory. Fixed Bugs ---------- * TEXT-232: WordUtils.containsAllWords?() may throw PatternSyntaxException. Thanks to Arnout Engelen, Gary Gregory. * TEXT-175: Fix regression for determining whitespace in WordUtils #519. Thanks to David Lavati, seanfabs, Gary Gregory, Bruno P. Kinoshita. * Deprecate Builder in favor of Supplier. Thanks to Gary Gregory. Changes ------- * Bump commons-lang3 from 3.13.0 to 3.14.0. Thanks to Gary Gregory. * Bump commons.bytebuddy.version from 1.14.9 to 1.14.13 #476, #482, #505, #521. Thanks to Dependabot. * Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.2.0 #474, #508. Thanks to Dependabot. * Bump commons-io from 2.15.0 to 2.16.1 #522, #527. Thanks to Gary Gregory. * Bump commons-parent from 64 to 69 #524. Thanks to Gary Gregory. * Bump org.assertj:assertj-core from 3.24.2 to 3.25.3. Thanks to Dependabot. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ----------------------------------------------------------------------------- Apache Commons Text Version 1.11.0 Release Notes ------------------------------------------------ This document contains the release notes for the 1.11.0 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. Apache Commons Text is a library focused on algorithms working on strings. Release 1.11.0. Requires Java 8 or above. New features ------------ * TEXT-224: Set SecureProcessing feature in XmlStringLookup by default. Thanks to PJ Fanning, Gary Gregory. * TEXT-224: Add StringLookupFactory.xmlStringLookup(Map...). Thanks to Gary Gregory. * Add @FunctionalInterface to FormatFactory. Thanks to Gary Gregory. * Add RandomStringGenerator.builder(). Thanks to Gary Gregory. * TEXT-229: Add XmlEncoderStringLookup/XmlDecoderStringLookup #449. Thanks to Michael Osipov, Elliotte Rusty Harold, Gary Gregory. * Add StringSubstitutor.toString(). Thanks to Gary Gregory. Fixed Bugs ---------- * TEXT-219: Fix StringTokenizer.getTokenList to return an independent modifiable list Thanks to Jaap Sperling. * Fix Javadoc for StringEscapeUtils.escapeHtml4 #382 Thanks to James Nord. * TextStringBuidler#hashCode() allocates a String on each call #387. Thanks to Pavel Belousov, Gary Gregory. * TEXT-221: Fix Bundle-SymbolicName to use the package name org.apache.commons.text Thanks to Remco Riswick. * Add and use a package-private singleton for RegexTokenizer. Thanks to Gary Gregory. * Add and use a package-private singleton for CosineSimilarity. Thanks to Gary Gregory. * Add and use a package-private singleton for LongestCommonSubsequence. Thanks to Gary Gregory. * Add and use a package-private singleton for JaroWinklerSimilarity. Thanks to Gary Gregory. * Add and use a package-private singleton for JaccardSimilarity. Thanks to Gary Gregory. * [StepSecurity] ci: Harden GitHub Actions #428. Thanks to step-security-bot, Gary Gregory. * Improve AlphabetConverter Javadoc #429. Thanks to Dimitrios Efthymiou. * Fix exception message in IntersectionResult to make set-theoretic sense #438. Thanks to Dimitrios Efthymiou. * Add null-check in RandomStringGenerator#Builder#selectFrom() to avoid NullPointerException #434. Thanks to Dimitrios Efthymiou, Gary Gregory. * Add null-check in RandomStringGenerator#Builder#withinRange() to avoid NullPointerException. Thanks to Dimitrios Efthymiou, Gary Gregory. * TEXT-228: Fix TextStringBuilder to over-allocate when ensuring capacity #452. Thanks to Alex Herbert, Gary Gregory. * Constructor for ResourceBundleStringLookup should be private instead of package-private. Thanks to Elliotte Rusty Harold, Gary Gregory. * Constructor for UrlDecoderStringLookup should be private instead of package-private. Thanks to Elliotte Rusty Harold, Gary Gregory. * Constructor for UrlEncoderStringLookup should be private instead of package-private. Thanks to Elliotte Rusty Harold, Gary Gregory. * TEXT-230: Javadoc of org.apache.commons.text.lookup.DefaultStringLookup.XML is incorrect. Thanks to Michael Osipov, Gary Gregory. * Update DoubleFormat to state it is based on Double.toString. #467. Thanks to Alex Herbert. Changes ------- * Bump actions/cache. Thanks to Dependabot. * Bump actions/setup-java. Thanks to Dependabot. * Bump actions/checkout. Thanks to Dependabot. * Bump pmd from 6.49.0 to 6.52.0 #364. Thanks to Dependabot, Gary Gregory. * Bump commons-rng-simple from 1.4 to 1.5 #370. Thanks to Dependabot. * Bump spotbugs-maven-plugin from 4.7.2.0 to 4.7.3.6 #371, #385. Thanks to Dependabot, Gary Gregory. * Bump spotbugs from 4.7.2 to 4.7.3 #373. Thanks to Dependabot. * Bump mockito-inline from 4.8.0 to 4.11.0 #380, #389, #396, #400. Thanks to Dependabot. * Bump jmh.version from 1.35 to 1.37 #388. Thanks to Dependabot. * Bump commons-parent from 54 to 64 #392, #401. Thanks to Gary Gregory. * Bump assertj-core from 3.23.1 to 3.24.2 #405, #410. Thanks to Dependabot. * Bump maven-checkstyle-plugin from 3.2.0 to 3.2.1 #407. Thanks to Dependabot. * Bump commons-io from 2.11.0 to 2.14.0. Thanks to Gary Gregory. * Bump commons-lang3 from 3.12.0 to 3.13.0. Thanks to Gary Gregory. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.10.0 Release Notes ------------------------------------------------ This document contains the release notes for the 1.10.0 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. Apache Commons Text is a library focused on algorithms working on strings. Release 1.10.0. Requires Java 8 or above. Changes in this version include: New features ------------ * TEXT-207: Add DoubleFormat utility. * TEXT-190: Document negative limit for WordUtils abbreviate method Thanks to Benjamin Bing. * TEXT-188: Speed up LevenshteinDistance with threshold by exiting early Thanks to Jakob Vesterstrøm. * TEXT-185: Release Notes page hasn't been updated for 1.9 release yet. Thanks to Larry West, Gary Gregory. * Add StrBuilder.isNotEmpty(). Thanks to Gary Gregory. Fixed Bugs ---------- * TEXT-189: Fix CaseUtils when the input string contains only delimiters Thanks to Gongpu Zhu. * TEXT-187: Add GraalVM test dependencies to fix test failures with Java 15. * TEXT-158: Incorrect values for Jaccard similarity with empty strings. * TEXT-186: StringSubstitutor map constructor throws NPE on 1.9 with null map. Thanks to Gautam Korlam, Gary Gregory. * TEXT-191: JaroWinklerDistance returns the same values as JaroWinklerSimilarity. Thanks to Bradley David Rumball. * Correct Javadoc in FileStringLookup. Thanks to Gary Gregory. * Minor Improvements #192, #196. Thanks to Arturo Bernal. * TEXT-194: Use StringUtils.INDEX_NOT_FOUND constant. Thanks to Arturo Bernal. * TEXT-199: Remove redundant local variable. Thanks to Arturo Bernal. * TEXT-198: Replace lambda with method reference. Thanks to Arturo Bernal. * TEXT-200: Simplify statements. Thanks to Arturo Bernal. * TEXT-197: Replace statement lambda with expression lambda. Thanks to Arturo Bernal. * TEXT-204: Use static class inner class in tests. Thanks to Arturo Bernal. * TEXT-201: Simplify assertion. Thanks to Arturo Bernal. * TEXT-202: Extract duplicate code. Thanks to Arturo Bernal. * TEXT-205: Set void return method. Thanks to Arturo Bernal. * Remove unused exception from TextStringBuilder.readFrom(CharBuffer). This preserves binary compatibility but not source compatibility. Thanks to Gary Gregory. * StrBuilder.StrBuilderReader.skip(long): Throw an exception when an implicit narrowing conversion in a compound assignment would result in information loss or a numeric error such as an overflows. Thanks to CodeQL, Gary Gregory. * TextStringBuilder.TextStringBuilderReader.skip(long): Throw an exception when an implicit narrowing conversion in a compound assignment would result in information loss or a numeric error such as an overflows. Thanks to CodeQL, Gary Gregory. * TEXT-211: TextStringBuilder.equals whatever the capacity is #281. Thanks to sebx59. * TEXT=212: A More Efficient Implementation for Calculating Size of Longest Common Subsequence. Thanks to Ali Ghanbari. * TEXT-209: LookupTranslator returns count of chars consumed, not of codepoints consumed. Thanks to fourAjeff. * TEXT-209: Use Math.min() call instead of doing it manually. #335. Thanks to Arturo Bernal. * TextStringBuilder: Throw OutOfMemoryError instead of NegativeArraySizeException. Thanks to ValentijnvdBeek, Gary Gregory. * TextStringBuilder: Can't grow to sizes up to Integer.MAX_VALUE. Thanks to ValentijnvdBeek, Gary Gregory. * Make default string lookups configurable via system property. Remove dns, url, and script lookups from defaults. If these lookups are required for use in StringSubstitutor.createInterpolator(), they must be enabled via system property. See StringLookupFactory for details. Changes ------- * Bump actions/setup-java from v1.4.0 to 3 #147, #156, #155, #172, #215, #314. Thanks to Dependabot. * Bump github/codeql-action from 1 to 2 #319. Thanks to Dependabot. * Bump checkstyle from 8.34 to 9.3, #141, #168, #182, #188, #193, #201, #208, #211, #228, #235, #245, #253, #255, #262, #270, #280, #287, #299, #315, #321. Thanks to Dependabot. * Bump spotbugs-maven-plugin from 4.0.0 to 4.7.2.0, #144, #150, #167, #176, #194, #210, #223, #250, #268, #273, #277, #278, #286, #293, #303, #320, #325, #338, #344, #354. Thanks to Gary Gregory, Dependabot. * Bump spotbugs from 4.1.3 to 4.7.2 #175, 189, #209, #218, #247, #256, #264, #275, #284, #289, #296, #306, #355. Thanks to Gary Gregory, Dependabot. * Bump mockito-inline from 3.4.4 to 4.8.0, #143, #148, #149, #152, #153, #154, #158, #159, #166, #177, #180, #187, #195, #197, #207, #216, #231, #236, #237, #243, #258, #259, #260, #261, #272, #285, #291, #305, #317, #330, #331, #347, #352. Thanks to Dependabot. * Bump junit-jupiter from 5.6.2 to 5.9.1 #163, #204, #232, #265, #269, #288, #343, #357. Thanks to Dependabot. * Bump assertj-core from 3.16.1 to 3.23.1 #151, #157, #160, #178, #184, #199, #244, #267, #294. Thanks to Dependabot, Gary Gregory. * Bump commons-io from 2.7 to 2.11.0 #161 #251. Thanks to Dependabot, Gary Gregory. * Bump commons-parent from 51 to 54 #145, #358. Thanks to Dependabot, Gary Gregory. * Bump maven-pmd-plugin from 3.13.0 to 3.19.0 #186, #263, #302, #334, #349, #353. Thanks to Dependabot. * Bump pmd from 6.42.0 to 6.46.0. Thanks to Gary Gregory. * Bump graalvm.version from 20.2.0 to 22.0.0.2 #185, #198, #206, #227, #252, #276, #295, #300. Thanks to Dependabot. * Bump commons.japicmp.version from 0.14.3 to 0.16.0. Thanks to Gary Gregory. * Bump commons.jacoco.version 0.8.5 to 0.8.8; fixes Java 15 build. Thanks to Gary Gregory. * Bump maven-checkstyle-plugin from 3.1.1 to 3.2.0 #202, #348. Thanks to Dependabot. * Bump commons-lang3 3.11 -> 3.12.0. Thanks to Gary Gregory. * Bump commons.javadoc.version from 3.2.0 to 3.4.1. Thanks to Gary Gregory. * Bump commons.project-info.version from 3.1.0 to 3.1.2. Thanks to Gary Gregory. * Bump jmh.version from 1.32 to 1.35 #254, #292, #313. Thanks to Dependabot. * Bump commons-rng-simple from 1.3 to 1.4 #266. Thanks to Dependabot. * Bump taglist-maven-plugin from 2.4 to 3.0.0 #297. Thanks to Dependabot. * Bump commons.pmd-impl.version from 6.44.0 to 6.49.0 #323, #336, #345, #350. Thanks to Dependabot. * Bump exec-maven-plugin from 3.0.0 to 3.1.0 #340. Thanks to Dependabot. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.9 Release Notes --------------------------------------------- This document contains the release notes for the 1.9 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. Apache Commons Text is a library focused on algorithms working on strings. Release 1.9. Requires Java 8 or above. Changes in this version include: New features ------------ * Add StringMatcher.size(). Thanks to Gary Gregory. * Refactor TextStringBuilder.readFrom(Readable), extracting readFrom(CharBuffer) and readFrom(Reader). Thanks to Gary Gregory. * Add BiStringLookup and implementation BiFunctionStringLookup. Thanks to Gary Gregory. * Add org.apache.commons.text.StringSubstitutor.StringSubstitutor(StringSubstitutor). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.TextStringBuilder(CharSequence). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.drainChar(int). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.drainChars(int, int, char[]. int). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.isNotEmpty(). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.isReallocated(). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.readFrom(Reader, int). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.set(String). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.wrap(char[]). Thanks to Gary Gregory. * Add org.apache.commons.text.TextStringBuilder.wrap(char[], int). Thanks to Gary Gregory. * Add org.apache.commons.text.io.StringSubstitutorReader. Thanks to Gary Gregory. * Add org.apache.commons.text.lookup.StringLookupFactory.functionStringLookup(Function). Thanks to Gary Gregory. * Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int). Thanks to Gary Gregory. * Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int, int, int). Thanks to Gary Gregory. * Add org.apache.commons.text.matcher.StringMatcherFactory.andMatcher(StringMatcher...). Thanks to Gary Gregory. * Add org.apache.commons.text.matcher.StringMatcherFactory.stringMatcher(char...). Thanks to Gary Gregory. Fixed Bugs ---------- * TEXT-166: Removed non-existing parameter from Javadocs and spelled out parameters in throws. Thanks to Mikko Maunu. * TEXT-149: StringEscapeUtils.unescapeCsv doesn't remove quotes at begin and end of string. Thanks to Yuji Konishi. * TEXT-174: ScriptStringLookup does not accept ":" #126. Thanks to furkilic. * TEXT-178: StringSubstitutor incorrectly removes some escape characters. Thanks to Gary Gregory. * TEXT-181: Fix Javadocs #135. Thanks to XenoAmess. * TEXT-182: Fix typos #137. Thanks to XenoAmess. * TEXT-183: Make ConstantStringLookup.constantCache final #136. Thanks to XenoAmess. * TEXT-184: Simplify if in CaseUtils #134. Thanks to XenoAmess. Changes ------- * [javadoc] Fix compiler warnings in Java code example in Javadoc #124. Thanks to Johan Hammar. * TEXT-177: Update from Apache Commons Lang 3.9 to 3.11. Thanks to Gary Gregory. * [build] Skip clirr since we use JApiCmp. Thanks to Gary Gregory. * [test] junit-jupiter 5.5.1 -> 5.5.2. Thanks to Gary Gregory. * [test] org.assertj:assertj-core 3.13.2 -> 3.16.1. Thanks to Gary Gregory. * [build] com.puppycrawl.tools:checkstyle 8.23 -> 8.34. Thanks to Gary Gregory. * [build] Update JUnit from 5.5.2 to 5.6.2. Thanks to Gary Gregory. * [build] commons.jacoco.version 0.8.4 -> 0.8.5. Thanks to Gary Gregory. * [build] commons.javadoc.version 3.1.1 -> 3.2.0. Thanks to Gary Gregory. * [build] commons.japicmp.version 0.14.1 -> 0.14.3. Thanks to Gary Gregory. * [build] checkstyle.plugin.version 3.1.0 -> 3.1.1. Thanks to Gary Gregory. * [build] checkstyle.version 8.27 -> 8.33. Thanks to Gary Gregory. * [build] org.apache.commons:commons-parent 48 -> 51. Thanks to Gary Gregory. * [build] maven-pmd-plugin 3.12.0 -> 3.13.0. Thanks to Gary Gregory. * [build] org.mockito 3.3.3 -> 3.4.4. Thanks to Gary Gregory. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download page: https://commons.apache.org/proper/commons-text/download_text.cgi Have fun! -Apache Commons Team ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.8 Release Notes --------------------------------------------- This document contains the release notes for the 1.8 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. Apache Commons Text is a library focused on algorithms working on strings. Release 1.8 Changes in this version include: New Features ------------ * TEXT-169: Add helper factory method org.apache.commons.text.StringSubstitutor.createInterpolator(). Thanks to Gary Gregory. * TEXT-170: Add String lookup for host names and IP addresses (DnsStringLookup). Thanks to Gary Gregory. Fixed Bugs ---------- * TEXT-167: commons-text web page missing "RELEASE-NOTES-1.7.txt". Thanks to Larry West. * TEXT-168: (doc) Fixed wrong value for Jaro-Winkler example #117. Thanks to luksan47. * TEXT-171: StringLookupFactory.addDefaultStringLookups(Map) does not convert keys to lower case. Thanks to Gary Gregory. Changes ------- * Expand Javadoc for StringSubstitutor and friends. Thanks to Gary Gregory. * [site] checkstyle.version 8.21 -> 8.23. Thanks to Gary Gregory. Historical list of changes: https://commons.apache.org/proper/commons-textchanges-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download it from https://commons.apache.org/proper/commons-text/download_text.cgi ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.7 Release Notes --------------------------------------------- This document contains the release notes for the 1.7 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. Apache Commons Text is a library focused on algorithms working on strings. Changes in this version include: New features ------------ * TEXT-148: Add an enum to the lookup package that lists all StringLookups * TEXT-127: Add a toggle to throw an exception when a variable is unknown in StringSubstitutor Thanks to Jean-Baptiste REICH, Sebb, Don Jeba, Gary Gregory. * TEXT-138: TextStringBuilder append sub-sequence not consistent with Appendable. Thanks to Neal Johnson, Don Jeba. * TEXT-152: Fix possible infinite loop in WordUtils.wrap for a regex pattern that would trigger on a match of 0 length Thanks to @CAPS50. * TEXT-155: Add a generic IntersectionSimilarity measure Fixed Bugs ---------- * TEXT-111: WordUtils.wrap must calculate offset increment from wrapOn pattern length Thanks to @CAPS50. * TEXT-151: Fix the JaroWinklerSimilarity to use StringUtils.equals to test for CharSequence equality * TEXT-165: ResourceBundleStringLookup.lookup(String) throws MissingResourceException instead of returning null. Changes ------- * TEXT-104: Jaro Winkler Distance refers to similarity Thanks to Sascha Szott. * TEXT-153: Make prefixSet in LookupTranslator a BitSet Thanks to amirhadadi. * TEXT-156: Fix the RegexTokenizer to use a static Pattern * TEXT-157: Remove rounding from JaccardDistance and JaccardSimilarity * TEXT-162: Update Apache Commons Lang from 3.8.1 to 3.9. * Update tests from org.assertj:assertj-core 3.12.1 to 3.12.2. * Update site from com.puppycrawl.tools:checkstyle 8.18 to 8.21. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text Download it from https://commons.apache.org/proper/commons-text/download_text.cgi ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.6 Release Notes --------------------------------------------- This document contains the release notes for the 1.6 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. This release requires Java 8. Changes ------- * TEXT-144: Add the resource string bundle string lookup to the default set of lookups * TEXT-145: Add StringLookupFactory methods for the URL encoder and decoder string lookups * TEXT-146: org.apache.commons.text.lookup.StringLookupFactory.interpolatorStringLookup() should reuse a singleton instance * TEXT-147: Add a Base64 encoder string lookup. Historical list of changes: https://commons.apache.org/proper/commons-text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Commons Text website: https://commons.apache.org/proper/commons-text ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.5 Release Notes --------------------------------------------- This document contains the release notes for the 1.5 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. This release requires Java 8. New Features ------------ * TEXT-133: Add a XML file XPath string lookup. * TEXT-134: Add a Properties file string lookup. * TEXT-135: Add a script string lookup. * TEXT-136: Add a file string lookup. * TEXT-137: Add a URL string lookup. * TEXT-140: Add a Base64 string lookup. * TEXT-141: Add org.apache.commons.text.lookup.StringLookupFactory.resourceBundleStringLookup(String). * TEXT-142: Add URL encoder and decoder string lookups. * TEXT-143: Add constant string lookup like the one in Apache Commons Configuration. Fixed Bugs ---------- * TEXT-139: Improve JaccardSimilarity computational cost Thanks to Nick Wong. * TEXT-118: JSON escaping incorrect for the delete control character Thanks to Nandor Kollar. * TEXT-130: Fixes JaroWinklerDistance: Wrong results due to precision of transpositions Thanks to Jan Martin Keil. * TEXT-131: JaroWinklerDistance: Calculation deviates from definition Thanks to Jan Martin Keil. Changes ------- * TEXT-132: Update Apache Commons Lang from 3.7 to 3.8.1 ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.4 Release Notes --------------------------------------------- This document contains the release notes for the 1.4 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. This release requires Java 8. Changes in this version include: Fixed Bugs ---------- * TEXT-120: StringEscapeUtils#unescapeJson does not unescape double quotes and forward slash. * TEXT-119: Remove mention of SQL escaping from user guide. * TEXT-123: WordUtils.wrap throws StringIndexOutOfBoundsException when wrapLength is Integer.MAX_VALUE. Thanks to Takanobu Asanuma. Changes ------- * TEXT-121: Update Java requirement from version 7 to 8. Thanks to pschumacher. * TEXT-122: Allow full customization with new API org.apache.commons.text.lookup.StringLookupFactory.interpolatorStringLookup(Map, StringLookup, boolean). ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.3 Release Notes --------------------------------------------- This document contains the release notes for the 1.3 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. This release requires Java 7. New Features ------------ * Add Automatic-Module-Name MANIFEST entry for Java 9 compatibility Issue: TEXT-110. * Add an interpolator string lookup: StringLookupFactory#interpolatorStringLookup() Issue: TEXT-113. * Add a StrSubstitutor replacement based on interfaces: StringSubstitutor Issue: TEXT-114. * Add a StrBuilder replacement based on the StringMatcher interface: TextStringBuilder Issue: TEXT-115. * Add a StrTokenizer replacement based on the StringMatcher interface: StringTokenizer Issue: TEXT-116. * Add a local host string lookup: LocalHostStringLookup Issue: TEXT-117. Fixed Bugs ---------- * Build failure with java 9-ea+159 Issue: TEXT-70. * StrLookup API confusing Issue: TEXT-80. ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.2 Release Notes --------------------------------------------- This document contains the release notes for the 1.2 version of Apache Commons Text. Commons Text is a set of utility functions and reusable components for the purpose of processing and manipulating text that should be of use in a Java environment. This release requires Java 7. Java 9 Support -------------- At our time of release of 1.1, our build succeeds with Java 9-ea build 159, and we believe all of our features to be Java 9 compatible. However, when we run "mvn clean site" we have failures. New Features ------------ * TEXT-74: StrSubstitutor: Ability to turn off substitution in values. Thanks to Ioannis Sermetziadis. * TEXT-97: RandomStringGenerator able to pass multiple ranges to .withinRange(). Thanks to Amey Jadiye. * TEXT-89: WordUtils.initials support for UTF-16 surrogate pairs. Thanks to Arun Vinud S S. * TEXT-90: Add CharacterPredicates for ASCII letters (uppercase/lowercase) and arabic numerals. * TEXT-85: Added CaseUtils class with camel case conversion support. Thanks to Arun Vinud S S. * TEXT-91: RandomStringGenerator should be able to generate a String with a random length. * TEXT-102: Add StrLookup.resourceBundleLookup(ResourceBundle). Fixed Bugs ---------- * TEXT-106: Exception thrown in ExtendedMessageFormat using quotes with custom registry. Thanks to Benoit Moreau. * TEXT-100: StringEscapeUtils#UnEscapeJson doesn't recognize escape signs correctly. Thanks to Don Jeba. * TEXT-105: Typo in LongestCommonSubsequence#logestCommonSubsequence. Thanks to Abrasha. Changes ------- * TEXT-107: Upversion commons-lang to 3.7. * TEXT-98: Deprecate isDelimiter and use HashSets for delimiter checks. Thanks to Arun Vinud S S. * TEXT-88: WordUtils should treat an empty delimiter array as no delimiters. Thanks to Amey Jadiye. * TEXT-93: Update RandomStringGenerator to accept a list of valid characters. Thanks to Amey Jadiye. * TEXT-92: Update commons-lang dependency to version 3.6. * TEXT-83: Document that commons-csv should be used in preference to CsvTranslators. Thanks to Amey Jadiye. * TEXT-67: NumericEntityUnescaper.options - fix TODO. * TEXT-84: RandomStringGenerator claims to be immutable, but isn't. ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.1 Release Notes --------------------------------------------- Java 9 Support -------------- At our time of release of 1.1, our build succeeds with Java 9-ea build 159, and we believe all of our features to be Java 9 compatible. However, when we run "mvn clean site" we have failures. New Features ------------ * TEXT-41: WordUtils.abbreviate support Thanks to Amey Jadiye. * TEXT-82: Putting WordUtils back in to the codebase Thanks to Amey Jadiye. * TEXT-81: Add RandomStringGenerator Thanks to djones. * TEXT-36: RandomStringGenerator: allow users to provide source of randomness Thanks to Raymond DeCampo. Fixed Bugs ---------- * TEXT-76: Correct round issue in Jaro Winkler implementation * TEXT-72: Similar to LANG-1025, clirr fails site build. CHANGES ======= * TEXT-39: WordUtils should use toXxxxCase(int) rather than toXxxxCase(char) Thanks to Amey Jadiye. ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.0 Release Notes --------------------------------------------- Incompatible Changes -------------------- All package names changed from org.apache.commons.text.beta in 1.0-beta-1 to org.apache.commons.text in 1.0. Methods StringEscapeUtils#escapeHtml3Once and StringEscapeUtils#escapeHtml4Once have been removed; see TEXT-40 Java 9 Support -------------- At our time of release of 1.0, our build succeeds with Java 9-ea build 158, and we believe all of our features to be Java 9 compatible. However, when we run "mvn clean site" we have failures. Fixed Bugs ---------- * TEXT-64: Investigate locale issue in ExtendedMessageFormatTest. Thanks to chtompki. * TEXT-69: Resolve PMD/CMD Violations * TEXT-65: Fixing the 200 checkstyle errors present in 1.0-beta-1. * TEXT-63: Mutable fields should be private. Removed ------- * TEXT-40: Escape HTML characters only once: revert. ------------------------------------------------------------------------------------------------------- Apache Commons Text Version 1.0-beta-1 Release Notes ---------------------------------------------------- A note on the History of the Code --------------------------------- The codebase began in the fall of 2014 as a location for housing algorithms for *perating on Strings that seemed to have a more complex nature than those which would be considered a needed extension to java.lang. Thus, a new component, different from Apache Commons Lang was warranted. As the project evolved, it was noticed that Commons Lang had considerable more text manipulation tools than the average Java application developer would need or even want. So, we have decided to move the more esoteric String processing algorithms out of Commons Lang into Commons Text. Java 9 Support -------------- At our time of release of 1.0-beta-1, our build succeeds with Java 9-ea build 153, and we believe all of our features to be Java 9 compatible. New Features ------------ * TEXT-56: Move CvsTranslators out of StringEscapeUtils and make them DRY Thanks to Jarek Strzeleck. * TEXT-40: Escape HTML characters only once Thanks to Sampanna Kahu. * TEXT-32: Add LCS similarity and distance * TEXT-34: Add class to generate random strings * TEXT-29: Add a builder to StringEscapeUtils * TEXT-28: Add shell/XSI escape/unescape support * TEXT-2: Add Jaccard Index and Jaccard Distance Thanks to Don Jeba. * TEXT-27: Move org.apache.commons.lang3.StringEscapeUtils.java into text * TEXT-23: Moving from commons-lang, the package org.apache.commons.lang3.text * TEXT-10: A more complex Levenshtein distance Thanks to Don Jeba. * TEXT-24: Add coveralls and Travis.ci integration * TEXT-19: Add alphabet converter Thanks to Eyal Allweil. * TEXT-13: Create Commons Text logo * TEXT-7: Write user guide * TEXT-15: Human name parser * TEXT-3: Add Cosine Similarity and Cosine Distance * TEXT-4: Port Myers algorithm from [collections] * TEXT-1: Add Hamming distance * TEXT-9: Incorporate String algorithms from Commons Lang Thanks to britter. Fixed Bugs ---------- Note. We recognize the curiosity of a new component having "fixed bugs," but a considerable number of files were migrated over from Commons Lang, some of which needed fixes. * TEXT-62: Incorporate suggestions from RC2 into 1.0 release. * TEXT-60: Upgrading Jacoco for Java 9-ea compatibility. Thanks to Lee Adcock. * TEXT-52: Possible attacks through StringEscapeUtils.escapeEcmaScrip better javadoc * TEXT-37: Global vs local source of randomness * TEXT-38: Fluent API in "RandomStringBuilder" * TEXT-26: Fix JaroWinklerDistance in the manner of LUCENE-1297 * TEXT-35: Unfinished class Javadoc for CosineDistance * TEXT-22: LevenshteinDistance reduce memory consumption * TEXT-5: IP clearance for the names package * TEXT-11: Work on the string metric, distance, and similarity definitions for the project * TEXT-12: Create StringDistanceFrom class that contains a StringMetric and the "left" side string. This would have a method that accepts the "right" side string to test. Thanks to Jonathan baker. * TEXT-8: Change (R) StringMetric.compare(CS left, CS right) to "apply" so that it is consistent with BiFunction. Thanks to Jonathan Baker. * TEXT-6: Allow extra information (e.g. Levenshtein threshold) to be stored as (final) fields in the StringMetric instance. Thanks to Jonathan Baker. Changes ------- * TEXT-61: Naming packages org.apache.commons.text.beta Thanks to Lee Adcock. * TEXT-58: Refactor EntityArrays to have unmodifiableMaps in leu of String[][] * TEXT-53: Prepare site for 1.0 release * TEXT-50: Upgrade from commons-parent version 41 to version 42 * TEXT-33: Consolidating since tags at 1.0, removing deprecated methods * TEXT-16: Improve HumanNameParser Removed ------- * TEXT-55: Remove WordUtils to be added back in an upcoming 1.X release * TEXT-51: Remove RandomStringGenerator to be added back in the 1.1 release * TEXT-31: Remove org.apache.commons.text.names, for later release than 1.0 Historical list of changes: https://commons.apache.org/text/changes-report.html For complete information on Apache Commons Text, including instructions on how to submit bug reports, patches, or suggestions for improvement, see the Apache Apache Commons Text website: https://commons.apache.org/text/ Have fun! -Apache Commons Text team ------------------------------------------------------------------------------------------------------- commons-text-rel-commons-text-1.15.0/SECURITY.md000066400000000000000000000016051511432740600212440ustar00rootroot00000000000000 The Apache Commons security page is [https://commons.apache.org/security.html](https://commons.apache.org/security.html). commons-text-rel-commons-text-1.15.0/pom.xml000066400000000000000000000562061511432740600207770ustar00rootroot00000000000000 4.0.0 org.apache.commons commons-parent 93 commons-text 1.15.0 Apache Commons Text Apache Commons Text is a set of utility functions and reusable components for processing and manipulating text in a Java environment. https://commons.apache.org/proper/commons-text ISO-8859-1 UTF-8 2025-12-04T15:53:46Z 1.8 1.8 text text org.apache.commons.text 1.15.0 1.15.1 (Java 8+) TEXT 12318221 text https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-text site-content 3.20.0 1.18.2 1.6 false 1.37 org.apache.commons.lang3;version="${commons.lang3.version}", org.apache.commons.lang3.function;version="${commons.lang3.version}", org.apache.commons.lang3.time;version="${commons.lang3.version}", * 1.14.0 RC1 true scm:svn:https://dist.apache.org/repos/dist/dev/commons/${commons.componentid} true 1.00 0.97 0.98 0.95 0.94 0.98 org.apache.commons commons-lang3 ${commons.lang3.version} org.junit.jupiter junit-jupiter test org.junit-pioneer junit-pioneer test net.bytebuddy byte-buddy ${commons.bytebuddy.version} test net.bytebuddy byte-buddy-agent ${commons.bytebuddy.version} test commons-io commons-io 2.21.0 test org.apache.commons commons-rng-simple ${commons.rng.version} test org.openjdk.jmh jmh-core ${jmh.version} test org.openjdk.jmh jmh-generator-annprocess ${jmh.version} test clean verify apache-rat:check japicmp:cmp checkstyle:check pmd:check spotbugs:check javadoc:javadoc org.apache.rat apache-rat-plugin site-content/** src/site/resources/download_text.cgi src/site/resources/release-notes/RELEASE-NOTES-*.txt src/test/resources/org/apache/commons/text/stringEscapeUtilsTestData.txt src/test/resources/org/apache/commons/text/lcs-perf-analysis-inputs.csv src/test/resources/org/apache/commons/text/oss-fuzz/** maven-pmd-plugin ${commons.pmd.version} ${maven.compiler.target} org.apache.maven.plugins maven-surefire-plugin false maven-checkstyle-plugin false src/conf/checkstyle.xml src/conf/checkstyle-header.txt src/conf/checkstyle-suppressions.xml src/conf/checkstyle-suppressions.xml true **/generated/**.java,**/jmh_generated/**.java com.github.spotbugs spotbugs-maven-plugin src/conf/spotbugs-exclude-filter.xml maven-assembly-plugin src/assembly/bin.xml src/assembly/src.xml gnu org.apache.maven.plugins maven-jar-plugin test-jar ${commons.module.name} org.apache.maven.plugins maven-scm-publish-plugin javadocs org.apache.maven.plugins maven-javadoc-plugin ${maven.compiler.source} maven-checkstyle-plugin false src/conf/checkstyle.xml src/conf/checkstyle-header.txt src/conf/checkstyle-suppressions.xml src/conf/checkstyle-suppressions.xml true **/generated/**.java,**/jmh_generated/**.java checkstyle com.github.spotbugs spotbugs-maven-plugin src/conf/spotbugs-exclude-filter.xml com.github.siom79.japicmp japicmp-maven-plugin maven-pmd-plugin ${maven.compiler.target} pmd cpd org.codehaus.mojo taglist-maven-plugin Needs Work TODO exact FIXME exact XXX exact Noteable Markers NOTE exact NOPMD exact NOSONAR exact 2014 kinow Bruno P. Kinoshita kinow@apache.org britter Benedikt Ritter britter@apache.org chtompki Rob Tompkins chtompki@apache.org ggregory Gary Gregory ggregory at apache.org https://www.garygregory.com The Apache Software Foundation https://www.apache.org/ PMC Member America/New_York https://people.apache.org/~ggregory/img/garydgregory80.png djones Duncan Jones djones@apache.org Don Jeba donjeba@yahoo.com Sampanna Kahu Jarek Strzelecki Lee Adcock Amey Jadiye ameyjadiye@gmail.com Arun Vinud S S Ioannis Sermetziadis Jostein Tveit Luciano Medallia Jan Martin Keil Nandor Kollar Nick Wong Ali Ghanbari https://ali-ghanbari.github.io/ scm:git:https://gitbox.apache.org/repos/asf/commons-text scm:git:https://gitbox.apache.org/repos/asf/commons-text https://gitbox.apache.org/repos/asf?p=commons-text.git https://issues.apache.org/jira/browse/TEXT apache.website Apache Commons Site scm:svn:https://svn.apache.org/repos/infra/websites/production/commons/content/proper/commons-text/ GitHub https://github.com/apache/commons-text/actions java-8-10 [1.8,10) 4.11.0 22.0.0.2 org.mockito mockito-inline ${commons.mockito.version} test org.graalvm.js js ${graalvm.version} test org.graalvm.js js-scriptengine ${graalvm.version} test java-11-21 [11,22) 5.2.0 22.3.5 org.mockito mockito-inline ${commons.mockito.version} test org.graalvm.js js ${graalvm.version} test org.graalvm.js js-scriptengine ${graalvm.version} test java-22-up [22,) 25.0.1 5.2.0 org.apache.maven.plugins maven-surefire-plugin true org.mockito mockito-inline ${commons.mockito.version} test org.graalvm.js js-language ${graalvm.version} test org.graalvm.truffle truffle-runtime ${graalvm.version} test org.graalvm.js js-scriptengine ${graalvm.version} test setup-checkout site-content org.apache.maven.plugins maven-antrun-plugin prepare-checkout run pre-site benchmark true org.apache org.codehaus.mojo exec-maven-plugin benchmark test exec test java -classpath org.openjdk.jmh.Main -rf json -rff target/jmh-result.${benchmark}.json ${benchmark} commons-text-rel-commons-text-1.15.0/src/000077500000000000000000000000001511432740600202405ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/assembly/000077500000000000000000000000001511432740600220575ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/assembly/bin.xml000066400000000000000000000034601511432740600233540ustar00rootroot00000000000000 bin tar.gz zip false LICENSE.txt NOTICE.txt RELEASE-NOTES.txt target *.jar 644 target/site/apidocs apidocs commons-text-rel-commons-text-1.15.0/src/assembly/src.xml000066400000000000000000000036471511432740600234020ustar00rootroot00000000000000 src tar.gz zip ${project.artifactId}-${commons.release.version}-src checkstyle.xml checkstyle-suppressions.xml CONTRIBUTING.md sb-excludes.xml LICENSE.txt checkstyle-header.txt NOTICE.txt pom.xml PROPOSAL.html README.md RELEASE-NOTES.txt src commons-text-rel-commons-text-1.15.0/src/changes/000077500000000000000000000000001511432740600216505ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/changes/changes.xml000066400000000000000000001536671511432740600240240ustar00rootroot00000000000000 Apache Commons Text Changes Fix exception message typo in XmlStringLookup.XmlStringLookup(Map, Path...). Inserting at the end of a TextStringBuilder throws a StringIndexOutOfBoundsException. Fix TextStringBuilderTest.testAppendToCharBuffer() to use proper argument type #724. Fix Apache RAT plugin console warnings. Fix site XML to use version 2.0.0 XML schema. Removed unreachable threshold verification code in src/main/java/org/apache/commons/text/similarity #730. Enable secure processing for the XML parser in XmlStringLookup in case the underlying JAXP implementation doesn't #729. Add experimental CycloneDX VEX file #683. Add Damerau-Levenshtein distance #687. Add unit tests to increase coverage #719. Add new test for CharSequenceTranslator#with() #725. Add tests and assertions to org.apache.commons.text.similarity to get to 100% code coverage #727, #728. Bump org.apache.commons:commons-parent from 85 to 93 #704, #723, #726. Bump commons.bytebuddy.version from 1.17.6 to 1.18.2 #696, #722. Bump graalvm.version from 24.2.2 to 25.0.1 #703, #716. Bump org.apache.commons:commons-lang3 from 3.18.0 to 3.20.0. Bump commons-io:commons-io from 2.20.0 to 2.21.0. Fix PMD UnnecessaryFullyQualifiedName in StringLookupFactory. Fix PMD UnnecessaryFullyQualifiedName in DefaultStringLookupsHolder. Fix PMD UnnecessaryFullyQualifiedName in PropertiesStringLookup. Fix PMD UnnecessaryFullyQualifiedName in JavaPlatformStringLookup. Fix PMD UnnecessaryFullyQualifiedName in StringSubstitutor. Fix PMD UnnecessaryFullyQualifiedName in StrSubstitutor. Fix PMD UnnecessaryFullyQualifiedName in AlphabetConverter. Fix PMD AvoidBranchingStatementAsLastInLoop in TextStringBuilder. Fix PMD AvoidBranchingStatementAsLastInLoop in StrBuilder. org.apache.commons.text.translate.LookupTranslator.LookupTranslator(Map CharSequence>) now throws NullPointerException instead of java.security.InvalidParameterException. Interface StringLookup now extends UnaryOperator<String>. Interface TextRandomProvider extends IntUnaryOperator. Add RandomStringGenerator.Builder.usingRandom(IntUnaryOperator). Add PMD check to default Maven goal. Add org.apache.commons.text.RandomStringGenerator.Builder.setAccumulate(boolean). Bump org.apache.commons:commons-parent from 81 to 85 #668. Bump commons-io:commons-io from 2.18.0 to 2.20.0. Bump graalvm.version from 24.2.0 to 24.2.2 #665, #681. Bump commons.bytebuddy.version from 1.17.5 to 1.17.6 (#677). Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0 #680. Remove -nouses directive from maven-bundle-plugin. OSGi package imports now state 'uses' definitions for package imports, this doesn't affect JPMS (from org.apache.commons:commons-parent:80). Deprecate EntityArrays.EntityArrays(). StringLookupFactory.DefaultStringLookupsHolder.createDefaultStringLookups() maps DefaultStringLookup.LOCAL_HOST twice instead of once for LOCAL_HOST and LOOPBACK_ADDRESS. Bump org.apache.commons:commons-parent from 79 to 81. Bump commons.bytebuddy.version from 1.16.1 to 1.17.5 #643, #659, #660. Bump graalvm.version from 24.1.2 to 24.2.0 #653. Add StringLookupFactory.loopbackAddressStringLookup(). Add StringLookupFactory.KEY_LOOPBACK_ADDRESS. Add DefaultStringLookup.LOOPBACK_ADDRESS. Add richer inputs in package org.apache.commons.text.similarity with SimilarityInput. Add HammingDistance.apply(SimilarityInput, SimilarityInput). Add JaccardDistance.apply(SimilarityInput, SimilarityInput). Add JaccardSimilarity.apply(SimilarityInput, SimilarityInput). Add JaroWinklerDistance.apply(SimilarityInput, SimilarityInput). Add JaroWinklerSimilarity.apply(SimilarityInput, SimilarityInput). Add LevenshteinDetailedDistance.apply(SimilarityInput, SimilarityInput). Add LevenshteinDistance.apply(SimilarityInput, SimilarityInput). Fix build on Java 22. Fix build on Java 23-ea. Make package-private constructor private: StrLookup.MapStrLookup.MapStrLookup(Map). Make package-private constructor private: StrLookup.SystemPropertiesStrLookup.SystemPropertiesStrLookup(). Make package-private class private and final: MapStrLookup. Make package-private class private: StrMatcher.CharMatcher. Make package-private class private: StrMatcher.CharSetMatcher. Make package-private class private: StrMatcher.NoMatcher. Make package-private class private: StrMatcher.StringMatcher. Make package-private class private: StrMatcher.TrimMatcher. Make package-private class private and final: IntersectionSimilarity.BagCount. Make package-private class private and final: IntersectionSimilarity.TinyCount. Deprecate LevenshteinDistance.LevenshteinDistance() in favor of LevenshteinDistance.getDefaultInstance(). Deprecate LevenshteinDetailedDistance.LevenshteinDetailedDistance() in favor of LevenshteinDetailedDistance.getDefaultInstance(). Improve StrBuilder documentation for new line text. Improve TextStringBuilder documentation for new line text #547. Required OSGi Import-Package version numbers in MANIFEST.MF #627. Bump org.apache.commons:commons-parent from 69 to 78 #542, #557, #571, #581, #584, #593, #600, #603, #614. Bump tests on Java >= 22 org.graalvm.*:* from 24.0.0 to 24.1.1 #592, #610. Bump commons.bytebuddy.version from 1.14.13 to 1.16.1 #538, #548, #553, #565, #579, #582, #585, #596, #597, #604, #612, #620, #623, #625, #640. Bump SpotBugs from 4.8.3 to 4.8.5. Bump org.assertj:assertj-core from 3.25.3 to 3.26.3 #554, #566. Bump org.codehaus.mojo:taglist-maven-plugin from 3.0.0 to 3.2.1 #564, #611. Bump org.apache.commons:commons-rng-simple from 1.5 to 1.6 #568. Bump org.apache.commons:commons-lang3 from 3.14.0 to 3.17.0 #569, #575, #586. Bump commons-io:commons-io from 2.16.1 to 2.18.0 #594, #628. Add StringLookupFactory.fileStringLookup(Path...) and deprecated fileStringLookup(). Add StringLookupFactory.propertiesStringLookup(Path...) and deprecated propertiesStringLookup(). Add StringLookupFactory.xmlStringLookup(Map, Path...) and deprecated xmlStringLookup() and xmlStringLookup(Map). Add StringLookupFactory.builder() for fencing Path resolution of the file, properties and XML lookups. Add DoubleFormat.Builder.get() as Builder now implements Supplier. WordUtils.containsAllWords​() may throw PatternSyntaxException. Fix regression for determining whitespace in WordUtils #519. Deprecate Builder in favor of Supplier. Bump commons-lang3 from 3.13.0 to 3.14.0. Bump commons.bytebuddy.version from 1.14.9 to 1.14.13 #476, #482, #505, #521. Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.2.0 #474, #508. Bump commons-io from 2.15.0 to 2.16.1 #522, #527. Bump commons-parent from 64 to 69 #524. Bump org.assertj:assertj-core from 3.24.2 to 3.25.3. Fix StringTokenizer.getTokenList to return an independent modifiable list Fix Javadoc for StringEscapeUtils.escapeHtml4 #382 TextStringBuidler#hashCode() allocates a String on each call #387. Fix Bundle-SymbolicName to use the package name org.apache.commons.text Add and use a package-private singleton for RegexTokenizer. Add and use a package-private singleton for CosineSimilarity. Add and use a package-private singleton for LongestCommonSubsequence. Add and use a package-private singleton for JaroWinklerSimilarity. Add and use a package-private singleton for JaccardSimilarity. [StepSecurity] ci: Harden GitHub Actions #428. Improve AlphabetConverter Javadoc #429. Fix exception message in IntersectionResult to make set-theoretic sense #438. Add null-check in RandomStringGenerator#Builder#selectFrom() to avoid NullPointerException #434. Add null-check in RandomStringGenerator#Builder#withinRange() to avoid NullPointerException. Fix TextStringBuilder to over-allocate when ensuring capacity #452. Constructor for ResourceBundleStringLookup should be private instead of package-private. Constructor for UrlDecoderStringLookup should be private instead of package-private. Constructor for UrlEncoderStringLookup should be private instead of package-private. Javadoc of org.apache.commons.text.lookup.DefaultStringLookup.XML is incorrect. Update DoubleFormat to state it is based on Double.toString. #467. Set SecureProcessing feature in XmlStringLookup by default. Add StringLookupFactory.xmlStringLookup(Map<String, Boolean>...). Add @FunctionalInterface to FormatFactory. Add RandomStringGenerator.builder(). Add XmlEncoderStringLookup/XmlDecoderStringLookup #449. Add StringSubstitutor.toString(). Bump actions/cache. Bump actions/setup-java. Bump actions/checkout. Bump pmd from 6.49.0 to 6.52.0 #364. Bump commons-rng-simple from 1.4 to 1.5 #370. Bump spotbugs-maven-plugin from 4.7.2.0 to 4.7.3.6 #371, #385. Bump spotbugs from 4.7.2 to 4.7.3 #373. Bump mockito-inline from 4.8.0 to 4.11.0 #380, #389, #396, #400. Bump jmh.version from 1.35 to 1.37 #388. Bump commons-parent from 54 to 64 #392, #401. Bump assertj-core from 3.23.1 to 3.24.2 #405, #410. Bump maven-checkstyle-plugin from 3.2.0 to 3.2.1 #407. Bump commons-io from 2.11.0 to 2.15.0. Bump commons-lang3 from 3.12.0 to 3.13.0. Fix CaseUtils when the input string contains only delimiters Add GraalVM test dependencies to fix test failures with Java 15. Incorrect values for Jaccard similarity with empty strings. StringSubstitutor map constructor throws NPE on 1.9 with null map. JaroWinklerDistance returns the same values as JaroWinklerSimilarity. Correct Javadoc in FileStringLookup. Minor Improvements #192, #196. Use StringUtils.INDEX_NOT_FOUND constant. Remove redundant local variable. Replace lambda with method reference. Simplify statements. Replace statement lambda with expression lambda. Use static class inner class in tests. Simplify assertion. Extract duplicate code. Set void return method. Remove unused exception from TextStringBuilder.readFrom(CharBuffer). This preserves binary compatibility but not source compatibility. StrBuilder.StrBuilderReader.skip(long): Throw an exception when an implicit narrowing conversion in a compound assignment would result in information loss or a numeric error such as an overflows. TextStringBuilder.TextStringBuilderReader.skip(long): Throw an exception when an implicit narrowing conversion in a compound assignment would result in information loss or a numeric error such as an overflows. TextStringBuilder.equals whatever the capacity is #281. A More Efficient Implementation for Calculating Size of Longest Common Subsequence. LookupTranslator returns count of chars consumed, not of codepoints consumed. Use Math.min() call instead of doing it manually. #335. TextStringBuilder: Throw OutOfMemoryError instead of NegativeArraySizeException. TextStringBuilder: Can't grow to sizes up to Integer.MAX_VALUE. Make default string lookups configurable via system property. Remove dns, url, and script lookups from defaults. If these lookups are required for use in StringSubstitutor.createInterpolator(), they must be enabled via system property. See StringLookupFactory for details. Add DoubleFormat utility. Document negative limit for WordUtils abbreviate method Speed up LevenshteinDistance with threshold by exiting early Release Notes page hasn't been updated for 1.9 release yet. Add StrBuilder.isNotEmpty(). Bump actions/setup-java from v1.4.0 to 3 #147, #156, #155, #172, #215, #314. Bump github/codeql-action from 1 to 2 #319. Bump checkstyle from 8.34 to 9.3, #141, #168, #182, #188, #193, #201, #208, #211, #228, #235, #245, #253, #255, #262, #270, #280, #287, #299, #315, #321. Bump spotbugs-maven-plugin from 4.0.0 to 4.7.2.0, #144, #150, #167, #176, #194, #210, #223, #250, #268, #273, #277, #278, #286, #293, #303, #320, #325, #338, #344, #354. Bump spotbugs from 4.1.3 to 4.7.2 #175, 189, #209, #218, #247, #256, #264, #275, #284, #289, #296, #306, #355. Bump mockito-inline from 3.4.4 to 4.8.0, #143, #148, #149, #152, #153, #154, #158, #159, #166, #177, #180, #187, #195, #197, #207, #216, #231, #236, #237, #243, #258, #259, #260, #261, #272, #285, #291, #305, #317, #330, #331, #347, #352. Bump junit-jupiter from 5.6.2 to 5.9.1 #163, #204, #232, #265, #269, #288, #343, #357. Bump assertj-core from 3.16.1 to 3.23.1 #151, #157, #160, #178, #184, #199, #244, #267, #294. Bump commons-io from 2.7 to 2.11.0 #161 #251. Bump commons-parent from 51 to 54 #145, #358. Bump maven-pmd-plugin from 3.13.0 to 3.19.0 #186, #263, #302, #334, #349, #353. Bump pmd from 6.42.0 to 6.46.0. Bump graalvm.version from 20.2.0 to 22.0.0.2 #185, #198, #206, #227, #252, #276, #295, #300. Bump commons.japicmp.version from 0.14.3 to 0.16.0. Bump commons.jacoco.version 0.8.5 to 0.8.8; fixes Java 15 build. Bump maven-checkstyle-plugin from 3.1.1 to 3.2.0 #202, #348. Bump commons-lang3 3.11 -> 3.12.0. Bump commons.javadoc.version from 3.2.0 to 3.4.1. Bump commons.project-info.version from 3.1.0 to 3.1.2. Bump jmh.version from 1.32 to 1.35 #254, #292, #313. Bump commons-rng-simple from 1.3 to 1.4 #266. Bump taglist-maven-plugin from 2.4 to 3.0.0 #297. Bump commons.pmd-impl.version from 6.44.0 to 6.49.0 #323, #336, #345, #350. Bump exec-maven-plugin from 3.0.0 to 3.1.0 #340. Removed non-existing parameter from Javadocs and spelled out parameters in throws. StringEscapeUtils.unescapeCsv doesn't remove quotes at begin and end of string. ScriptStringLookup does not accept ":" #126. StringSubstitutor incorrectly removes some escape characters. Fix Javadocs #135. Fix typos #137. Make ConstantStringLookup.constantCache final #136. Simplify if in CaseUtils #134. [javadoc] Fix compiler warnings in Java code example in Javadoc #124. Update from Apache Commons Lang 3.9 to 3.11. Add StringMatcher.size(). Refactor TextStringBuilder.readFrom(Readable), extracting readFrom(CharBuffer) and readFrom(Reader). Add BiStringLookup and implementation BiFunctionStringLookup. Add org.apache.commons.text.StringSubstitutor.StringSubstitutor(StringSubstitutor). Add org.apache.commons.text.TextStringBuilder.TextStringBuilder(CharSequence). Add org.apache.commons.text.TextStringBuilder.drainChar(int). Add org.apache.commons.text.TextStringBuilder.drainChars(int, int, char[]. int). Add org.apache.commons.text.TextStringBuilder.isNotEmpty(). Add org.apache.commons.text.TextStringBuilder.isReallocated(). Add org.apache.commons.text.TextStringBuilder.readFrom(Reader, int). Add org.apache.commons.text.TextStringBuilder.set(String). Add org.apache.commons.text.TextStringBuilder.wrap(char[]). Add org.apache.commons.text.TextStringBuilder.wrap(char[], int). Add org.apache.commons.text.io.StringSubstitutorReader. Add org.apache.commons.text.lookup.StringLookupFactory.functionStringLookup(Function<String, V>). Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int). Add org.apache.commons.text.matcher.StringMatcher.isMatch(CharSequence, int, int, int). Add org.apache.commons.text.matcher.StringMatcherFactory.andMatcher(StringMatcher...). Add org.apache.commons.text.matcher.StringMatcherFactory.stringMatcher(char...). [build] Skip clirr since we use JApiCmp. [test] junit-jupiter 5.5.1 -> 5.5.2. [test] org.assertj:assertj-core 3.13.2 -> 3.16.1. [build] com.puppycrawl.tools:checkstyle 8.23 -> 8.34. [build] Update JUnit from 5.5.2 to 5.6.2. [build] commons.jacoco.version 0.8.4 -> 0.8.5. [build] commons.javadoc.version 3.1.1 -> 3.2.0. [build] commons.japicmp.version 0.14.1 -> 0.14.3. [build] checkstyle.plugin.version 3.1.0 -> 3.1.1. [build] checkstyle.version 8.27 -> 8.33. [build] org.apache.commons:commons-parent 48 -> 51. [build] maven-pmd-plugin 3.12.0 -> 3.13.0. [build] org.mockito 3.3.3 -> 3.4.4. commons-text web page missing "RELEASE-NOTES-1.7.txt" (doc) Fixed wrong value for Jaro-Winkler example #117 Add helper factory method org.apache.commons.text.StringSubstitutor.createInterpolator(). Add String lookup for host names and IP addresses (DnsStringLookup). StringLookupFactory.addDefaultStringLookups(Map) does not convert keys to lower case. Expand Javadoc for StringSubstitutor and friends. [site] checkstyle.version 8.21 -> 8.23. WordUtils.wrap must calculate offset increment from wrapOn pattern length Jaro Winkler Distance refers to similarity Add an enum to the lookup package that lists all StringLookups Add a toggle to throw an exception when a variable is unknown in StringSubstitutor TextStringBuilder append sub-sequence not consistent with Appendable. Fix possible infinite loop in WordUtils.wrap for a regex pattern that would trigger on a match of 0 length Make prefixSet in LookupTranslator a BitSet Fix the RegexTokenizer to use a static Pattern Remove rounding from JaccardDistance and JaccardSimilarity Fix the JaroWinklerSimilarity to use StringUtils.equals to test for CharSequence equality Add a generic IntersectionSimilarity measure Update Apache Commons Lang from 3.8.1 to 3.9. ResourceBundleStringLookup.lookup(String) throws MissingResourceException instead of returning null. Update tests from org.assertj:assertj-core 3.12.1 to 3.12.2. Update site from com.puppycrawl.tools:checkstyle 8.18 to 8.21. Add the resource string bundle string lookup to the default set of lookups Add StringLookupFactory methods for the URL encoder and decoder string lookups org.apache.commons.text.lookup.StringLookupFactory.interpolatorStringLookup() should reuse a singleton instance Add a Base64 encoder string lookup. Improve JaccardSimilarity computational cost JSON escaping incorrect for the delete control character Fixes JaroWinklerDistance: Wrong results due to precision of transpositions JaroWinklerDistance: Calculation deviates from definition Update Apache Commons Lang from 3.7 to 3.8.1 Add a XML file XPath string lookup. Add a Properties file string lookup. Add a script string lookup. Add a file string lookup. Add a URL string lookup. Add a Base64 string lookup. Add org.apache.commons.text.lookup.StringLookupFactory.resourceBundleStringLookup(String). Add URL encoder and decoder string lookups. Add constant string lookup like the one in Apache Commons Configuration. StringEscapeUtils#unescapeJson does not unescape double quotes and forward slash Remove mention of SQL escaping from user guide Update Java requirement from version 7 to 8. Allow full customization with new API org.apache.commons.text.lookup.StringLookupFactory.interpolatorStringLookup(Map<String, StringLookup>, StringLookup, boolean). WordUtils.wrap throws StringIndexOutOfBoundsException when wrapLength is Integer.MAX_VALUE. Add Automatic-Module-Name MANIFEST entry for Java 9 compatibility Build failure with java 9-ea+159 Add an interpolator string lookup: StringLookupFactory#interpolatorStringLookup() Add a StrSubstitutor replacement based on interfaces: StringSubstitutor Add a StrBuilder replacement based on the StringMatcher interface: TextStringBuilder Add a StrTokenizer replacement based on the StringMatcher interface: StringTokenizer Add a local host string lookup: LocalHostStringLookup StrLookup API confusing Upversion commons-lang to 3.7 Exception thrown in ExtendedMessageFormat using quotes with custom registry StringEscapeUtils#UnEscapeJson doesn't recognize escape signs correctly StrSubstitutor: Ability to turn off substitution in values RandomStringGenerator able to pass multiple ranges to .withinRange() Deprecate isDelimiter and use HashSets for delimiter checks WordUtils.initials support for UTF-16 surrogate pairs WordUtils should treat an empty delimiter array as no delimiters Update RandomStringGenerator to accept a list of valid characters Add CharacterPredicates for ASCII letters (uppercase/lowercase) and arabic numerals Added CaseUtils class with camel case conversion support RandomStringGenerator should be able to generate a String with a random length Update commons-lang dependency to version 3.6 Document that commons-csv should be used in preference to CsvTranslators NumericEntityUnescaper.options - fix TODO RandomStringGenerator claims to be immutable, but isn't Add StrLookup.resourceBundleLookup(ResourceBundle) Typo in LongestCommonSubsequence#logestCommonSubsequence WordUtils should use toXxxxCase(int) rather than toXxxxCase(char) WordUtils.abbreviate support Putting WordUtils back in to the codebase Add RandomStringGenerator RandomStringGenerator: allow users to provide source of randomness Correct round issue in Jaro Winkler implementation Similar to LANG-1025, clirr fails site build. Investigate locale issue in ExtendedMessageFormatTest Resolve PMD/CMD Violations Escape HTML characters only once: revert Fixing the 200 checkstyle errors present in 1.0-beta-1 Mutable fields should be private Incorporate suggestions from RC2 into 1.0 release Naming packages org.apache.commons.text.beta Upgrading Jacoco for Java 9-ea compatibility. Refactor EntityArrays to have unmodifiableMaps in leu of String[][] Prepare site for 1.0 release Move CvsTranslators out of StringEscapeUtils and make them DRY Remove WordUtils to be added back in an upcoming 1.X release Possible attacks through StringEscapeUtils.escapeEcmaScrip better javadoc Remove RandomStringGenerator to be added back in the 1.1 release Upgrade from commons-parent version 41 to version 42 Escape HTML characters only once Global vs local source of randomness Fluent API in "RandomStringBuilder" Fix JaroWinklerDistance in the manner of LUCENE-1297 Add LCS similarity and distance Add class to generate random strings Unfinished class Javadoc for CosineDistance Consolidating since tags at 1.0, removing deprecated methods Add a builder to StringEscapeUtils Add shell/XSI escape/unescape support LevenshteinDistance reduce memory consumption Remove org.apache.commons.text.names, for later release than 1.0 Add Jaccard Index and Jaccard Distance Move org.apache.commons.lang3.StringEscapeUtils.java into text Moving from commons-lang, the package org.apache.commons.lang3.text A more complex Levenshtein distance Add coveralls and Travis.ci integration Add alphabet converter Create Commons Text logo Improve HumanNameParser IP clearance for the names package Write user guide Work on the string metric, distance, and similarity definitions for the project Human name parser Create StringDistanceFrom class that contains a StringMetric and the "left" side string. This would have a method that accepts the "right" side string to test. Add Cosine Similarity and Cosine Distance Change (R) StringMetric.compare(CS left, CS right) to "apply" so that it is consistent with BiFunction. Allow extra information (e.g. Levenshtein threshold) to be stored as (final) fields in the StringMetric instance. Port Myers algorithm from [collections] Add Hamming distance Incorporate String algorithms from Commons Lang commons-text-rel-commons-text-1.15.0/src/changes/release-notes.vm000066400000000000000000000104431511432740600247640ustar00rootroot00000000000000## Licensed to the Apache Software Foundation (ASF) under one ## or more contributor license agreements. See the NOTICE file ## distributed with this work for additional information ## regarding copyright ownership. The ASF licenses this file ## to you under the Apache License, Version 2.0 (the ## "License"); you may not use this file except in compliance ## with the License. You may obtain a copy of the License at ## ## https://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, ## software distributed under the License is distributed on an ## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ## KIND, either express or implied. See the License for the ## specific language governing permissions and limitations ## under the License. ## Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ${project.name} ${version} Release Notes ---------------------------------------- The ${developmentTeam} is pleased to announce the release of ${project.name} ${version}. $introduction.replaceAll("(? commons-text-rel-commons-text-1.15.0/src/conf/checkstyle.xml000066400000000000000000000157761511432740600240650ustar00rootroot00000000000000 commons-text-rel-commons-text-1.15.0/src/conf/security/000077500000000000000000000000001511432740600230345ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/conf/security/README.md000066400000000000000000000063131511432740600243160ustar00rootroot00000000000000 # CycloneDX Documents for Apache Commons Text The Apache Commons Text project publishes multiple [CycloneDX](https://cyclonedx.org/) documents to help consumers assess the security of their applications using this library: ## SBOM (Software Bill of Materials) Beginning with version `6.6.0`, Apache Commons Text publishes SBOMs in both **XML** and **JSON** formats to Maven Central. These documents describe all components and dependencies of the library, following standard Maven coordinates: * **Group ID:** `org.apache.commons` * **Artifact ID:** `commons-text` * **Classifier:** `cyclonedx` * **Type:** `xml` or `json` Each SBOM lists the library’s required and optional dependencies, helping consumers analyze the software supply chain and manage dependency risk. > [!NOTE] > The versions listed in the SBOM reflect the dependencies used during the build and test process for that specific release of Text. > Your own project may use different versions depending on your dependency management configuration. ## VEX (Vulnerability Exploitability eXchange) An experimental [VEX](https://cyclonedx.org/capabilities/vex/) document is also published: 👉 [`https://raw.githubusercontent.com/apache/commons-text/refs/heads/master/src/conf/security/VEX.cyclonedx.xml`](VEX.cyclonedx.xml) This document provides information about the **exploitability of known vulnerabilities** in the **dependencies** of Apache Commons Text. ### When is a dependency vulnerability exploitable? Because Apache Commons libraries (including Text) do **not** bundle their dependencies, a vulnerability in a dependency is only exploitable if **both** of the following conditions are true: 1. The vulnerable dependency is included in the consuming project. 2. Apache Commons Text is explicitly listed as affected by the vulnerability. ### Notes and Limitations * This VEX document is **experimental** and provided **as-is**. The semantics of this document may change in the future. * The **absence** of a vulnerability entry does **not** indicate that Text is unaffected. * If a version of Text is not listed under the `affects` section of a vulnerability, that version may still be affected or not. * Only the **latest major version** of Text is currently assessed for vulnerabilities. * The `analysis` field in the VEX file uses **Markdown** formatting. For more information about CycloneDX, SBOMs, or VEX, visit [cyclonedx.org](https://cyclonedx.org/). commons-text-rel-commons-text-1.15.0/src/conf/security/VEX.cyclonedx.xml000066400000000000000000000120661511432740600262140ustar00rootroot00000000000000 2025-08-04T11:45:36Z org.apache.commons commons-text cpe:2.3:a:apache:commons_text:*:*:*:*:*:*:*:* pkg:maven/org.apache.commons/commons-text?type=jar The Apache Software Foundation https://commons.apache.org Apache Commons PMC dev@commons.apache.org Apache Commons Security Team security@commons.apache.org CVE-2025-48924 GHSA-j288-q9x7-2f5v https://github.com/advisories/GHSA-j288-q9x7-2f5v exploitable update CVE-2025-48924 is exploitable in Apache Commons Text versions 1.5 and later, but only when all the following conditions are met: * The consuming project includes a vulnerable version of Commons Lang on the classpath. As of version `1.14.1`, Commons Text no longer references a vulnerable version of the `commons-lang3` library in its POM file. * Unvalidated or unsanitized user input is passed to the `StringSubstitutor` or `StringLookup` classes. * An interpolator lookup created via `StringLookupFactory.interpolatorLookup()` is used. If these conditions are satisfied, an attacker may cause an infinite loop by submitting a specially crafted input such as `${const:...}`. 2025-07-29T12:26:42Z 2025-07-29T12:26:42Z main_component =1.5|<2]]> affected Apache Commons PMC dev@commons.apache.org 2025-07-29T12:26:42Z This document provides information about the **exploitability of known vulnerabilities** in the **dependencies** of Apache Commons Text. # When is a dependency vulnerability exploitable? Because Apache Commons libraries do **not** bundle their dependencies, a vulnerability in a dependency is only exploitable if **both** of the following conditions are true: 1. The vulnerable dependency is included in the consuming project. 2. Apache Commons Text is explicitly listed as affected by the vulnerability. # Notes and Limitations * This VEX document is **experimental** and provided **as-is**. The semantics of this document may change in the future. * The **absence** of a vulnerability entry does **not** indicate that Text is unaffected. * If a version of Text is not listed under the `affects` section of a vulnerability, that version may still be affected or not. * Only the **latest major version** of Text is currently assessed for vulnerabilities. * The `analysis` field in the VEX file uses **Markdown** formatting. commons-text-rel-commons-text-1.15.0/src/conf/spotbugs-exclude-filter.xml000066400000000000000000000065231511432740600264750ustar00rootroot00000000000000 commons-text-rel-commons-text-1.15.0/src/main/000077500000000000000000000000001511432740600211645ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/000077500000000000000000000000001511432740600221055ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/000077500000000000000000000000001511432740600226745ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/000077500000000000000000000000001511432740600241155ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/000077500000000000000000000000001511432740600255705ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/000077500000000000000000000000001511432740600265545ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/AlphabetConverter.java000066400000000000000000000433211511432740600330320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; /** *

* Convert from one alphabet to another, with the possibility of leaving certain * characters unencoded. *

* *

* The target and 'do not encode' languages must be in the Unicode BMP, but the * source language does not. *

* *

* The encoding will all be of a fixed length, except for the 'do not encode' * chars, which will be of length 1 *

* *

Sample usage

* *
 * Character[] originals;   // a, b, c, d
 * Character[] encoding;    // 0, 1, d
 * Character[] doNotEncode; // d
 *
 * AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originals,
 * encoding, doNotEncode);
 *
 * ac.encode("a");    // 00
 * ac.encode("b");    // 01
 * ac.encode("c");    // 0d
 * ac.encode("d");    // d
 * ac.encode("abcd"); // 00010dd
 * 
* *

* #ThreadSafe# AlphabetConverter class methods are thread-safe as they do not * change internal state. *

* * @since 1.0 */ public final class AlphabetConverter { /** * Arrow constant, used for converting the object into a string. */ private static final String ARROW = " -> "; /** * Creates new String that contains just the given code point. * * @param i code point. * @return a new string with the new code point. * @see "http://www.oracle.com/us/technologies/java/supplementary-142654.html" */ private static String codePointToString(final int i) { if (Character.charCount(i) == 1) { return String.valueOf((char) i); } return new String(Character.toChars(i)); } /** * Converts characters to integers. * * @param chars array of characters. * @return an equivalent array of integers. */ private static Integer[] convertCharsToIntegers(final Character[] chars) { if (ArrayUtils.isEmpty(chars)) { return ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY; } final Integer[] integers = new Integer[chars.length]; Arrays.setAll(integers, i -> (int) chars[i]); return integers; } /** * Creates an alphabet converter, for converting from the original alphabet, to the encoded alphabet, while leaving the characters in doNotEncode * as they are (if possible). * *

* Duplicate letters in either original or encoding will be ignored. *

* * @param original an array of ints representing the original alphabet in code points. * @param encoding an array of ints representing the alphabet to be used for encoding, in code points. * @param doNotEncode an array of ints representing the chars to be encoded using the original alphabet - every char here must appear in both the previous * params. * @return The AlphabetConverter. * @throws IllegalArgumentException if an AlphabetConverter cannot be constructed. */ public static AlphabetConverter createConverter( final Integer[] original, final Integer[] encoding, final Integer[] doNotEncode) { final Set originalCopy = new LinkedHashSet<>(Arrays.asList(original)); final Set encodingCopy = new LinkedHashSet<>(Arrays.asList(encoding)); final Set doNotEncodeCopy = new LinkedHashSet<>(Arrays.asList(doNotEncode)); final Map originalToEncoded = new LinkedHashMap<>(); final Map encodedToOriginal = new LinkedHashMap<>(); final Map doNotEncodeMap = new HashMap<>(); final int encodedLetterLength; for (final int i : doNotEncodeCopy) { if (!originalCopy.contains(i)) { throw new IllegalArgumentException( "Can not use 'do not encode' list because original " + "alphabet does not contain '" + codePointToString(i) + "'"); } if (!encodingCopy.contains(i)) { throw new IllegalArgumentException( "Can not use 'do not encode' list because encoding alphabet does not contain '" + codePointToString(i) + "'"); } doNotEncodeMap.put(i, codePointToString(i)); } if (encodingCopy.size() >= originalCopy.size()) { encodedLetterLength = 1; final Iterator it = encodingCopy.iterator(); for (final int originalLetter : originalCopy) { final String originalLetterAsString = codePointToString(originalLetter); if (doNotEncodeMap.containsKey(originalLetter)) { originalToEncoded.put(originalLetter, originalLetterAsString); encodedToOriginal.put(originalLetterAsString, originalLetterAsString); } else { Integer next = it.next(); while (doNotEncodeCopy.contains(next)) { next = it.next(); } final String encodedLetter = codePointToString(next); originalToEncoded.put(originalLetter, encodedLetter); encodedToOriginal.put(encodedLetter, originalLetterAsString); } } return new AlphabetConverter(originalToEncoded, encodedToOriginal, encodedLetterLength); } if (encodingCopy.size() - doNotEncodeCopy.size() < 2) { throw new IllegalArgumentException( "Must have at least two encoding characters (excluding " + "those in the 'do not encode' list), but has " + (encodingCopy.size() - doNotEncodeCopy.size())); } // we start with one which is our minimum, and because we do the // first division outside the loop int lettersSoFar = 1; // the first division takes into account that the doNotEncode // letters can't be in the leftmost place int lettersLeft = (originalCopy.size() - doNotEncodeCopy.size()) / (encodingCopy.size() - doNotEncodeCopy.size()); while (lettersLeft / encodingCopy.size() >= 1) { lettersLeft /= encodingCopy.size(); lettersSoFar++; } encodedLetterLength = lettersSoFar + 1; final AlphabetConverter ac = new AlphabetConverter(originalToEncoded, encodedToOriginal, encodedLetterLength); ac.addSingleEncoding(encodedLetterLength, StringUtils.EMPTY, encodingCopy, originalCopy.iterator(), doNotEncodeMap); return ac; } /** * Creates an alphabet converter, for converting from the original alphabet, * to the encoded alphabet, while leaving the characters in * doNotEncode as they are (if possible). * *

Duplicate letters in either original or encoding will be ignored.

* * @param original an array of chars representing the original alphabet * @param encoding an array of chars representing the alphabet to be used * for encoding * @param doNotEncode an array of chars to be encoded using the original * alphabet - every char here must appear in * both the previous params * @return The AlphabetConverter * @throws IllegalArgumentException if an AlphabetConverter cannot be * constructed */ public static AlphabetConverter createConverterFromChars( final Character[] original, final Character[] encoding, final Character[] doNotEncode) { return createConverter( convertCharsToIntegers(original), convertCharsToIntegers(encoding), convertCharsToIntegers(doNotEncode)); } /** * Creates a new converter from a map. * * @param originalToEncoded a map returned from getOriginalToEncoded(). * @return The reconstructed AlphabetConverter. * @see AlphabetConverter#getOriginalToEncoded() */ public static AlphabetConverter createConverterFromMap(final Map originalToEncoded) { final Map unmodifiableOriginalToEncoded = Collections.unmodifiableMap(originalToEncoded); final Map encodedToOriginal = new LinkedHashMap<>(); int encodedLetterLength = 1; for (final Entry e : unmodifiableOriginalToEncoded.entrySet()) { encodedToOriginal.put(e.getValue(), codePointToString(e.getKey())); if (e.getValue().length() > encodedLetterLength) { encodedLetterLength = e.getValue().length(); } } return new AlphabetConverter(unmodifiableOriginalToEncoded, encodedToOriginal, encodedLetterLength); } /** * Original string to be encoded. */ private final Map originalToEncoded; /** * Encoding alphabet. */ private final Map encodedToOriginal; /** * Length of the encoded letter. */ private final int encodedLetterLength; /** * Hidden constructor for alphabet converter. Used by static helper methods. * * @param originalToEncoded original string to be encoded. * @param encodedToOriginal encoding alphabet. * @param encodedLetterLength length of the encoded letter. */ private AlphabetConverter(final Map originalToEncoded, final Map encodedToOriginal, final int encodedLetterLength) { this.originalToEncoded = originalToEncoded; this.encodedToOriginal = encodedToOriginal; this.encodedLetterLength = encodedLetterLength; } /** * Recursive method used when creating encoder/decoder. * * @param level at which point it should add a single encoding. * @param currentEncoding current encoding. * @param encoding letters encoding. * @param originals original values. * @param doNotEncodeMap map of values that should not be encoded. */ private void addSingleEncoding(final int level, final String currentEncoding, final Collection encoding, final Iterator originals, final Map doNotEncodeMap) { if (level > 0) { for (final int encodingLetter : encoding) { if (!originals.hasNext()) { return; // done encoding all the original alphabet } // this skips the doNotEncode chars if they are in the // leftmost place if (level != encodedLetterLength || !doNotEncodeMap.containsKey(encodingLetter)) { addSingleEncoding(level - 1, currentEncoding + codePointToString(encodingLetter), encoding, originals, doNotEncodeMap ); } } } else { Integer next = originals.next(); while (doNotEncodeMap.containsKey(next)) { final String originalLetterAsString = codePointToString(next); originalToEncoded.put(next, originalLetterAsString); encodedToOriginal.put(originalLetterAsString, originalLetterAsString); if (!originals.hasNext()) { return; } next = originals.next(); } final String originalLetterAsString = codePointToString(next); originalToEncoded.put(next, currentEncoding); encodedToOriginal.put(currentEncoding, originalLetterAsString); } } /** * Decodes a given string. * * @param encoded a string that has been encoded using this AlphabetConverter. * @return The decoded string, {@code null} if the given string is null. * @throws UnsupportedEncodingException if unexpected characters that cannot be handled are encountered. */ public String decode(final String encoded) throws UnsupportedEncodingException { if (encoded == null) { return null; } final StringBuilder result = new StringBuilder(); for (int j = 0; j < encoded.length();) { final int i = encoded.codePointAt(j); final String s = codePointToString(i); if (s.equals(originalToEncoded.get(i))) { result.append(s); j++; // because we do not encode in Unicode extended the // length of each encoded char is 1 } else { if (j + encodedLetterLength > encoded.length()) { throw new UnsupportedEncodingException("Unexpected end " + "of string while decoding " + encoded); } final String nextGroup = encoded.substring(j, j + encodedLetterLength); final String next = encodedToOriginal.get(nextGroup); if (next == null) { throw new UnsupportedEncodingException( "Unexpected string without decoding (" + nextGroup + ") in " + encoded); } result.append(next); j += encodedLetterLength; } } return result.toString(); } /** * Encodes a given string. * * @param original the string to be encoded. * @return The encoded string, {@code null} if the given string is null. * @throws UnsupportedEncodingException if chars that are not supported are encountered. */ public String encode(final String original) throws UnsupportedEncodingException { if (original == null) { return null; } final StringBuilder sb = new StringBuilder(); for (int i = 0; i < original.length();) { final int codePoint = original.codePointAt(i); final String nextLetter = originalToEncoded.get(codePoint); if (nextLetter == null) { throw new UnsupportedEncodingException( "Couldn't find encoding for '" + codePointToString(codePoint) + "' in " + original ); } sb.append(nextLetter); i += Character.charCount(codePoint); } return sb.toString(); } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } if (!(obj instanceof AlphabetConverter)) { return false; } final AlphabetConverter other = (AlphabetConverter) obj; return originalToEncoded.equals(other.originalToEncoded) && encodedToOriginal.equals(other.encodedToOriginal) && encodedLetterLength == other.encodedLetterLength; } /** * Gets the length of characters in the encoded alphabet that are necessary for each character in the original alphabet. * * @return The length of the encoded char. */ public int getEncodedCharLength() { return encodedLetterLength; } /** * Gets the mapping from integer code point of source language to encoded string. Use to reconstruct converter from serialized map. * * @return The original map. */ public Map getOriginalToEncoded() { return Collections.unmodifiableMap(originalToEncoded); } @Override public int hashCode() { return Objects.hash(originalToEncoded, encodedToOriginal, encodedLetterLength); } @Override public String toString() { final StringBuilder sb = new StringBuilder(); // @formatter:off originalToEncoded.forEach((k, v) -> sb.append(codePointToString(k)) .append(ARROW) .append(k) .append(System.lineSeparator())); // @formatter:on return sb.toString(); } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/Builder.java000066400000000000000000000056541511432740600310170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.function.Supplier; /** * Duplicates the functionality of {@link Supplier}. *

* Defines a class as a builder following the Builder design pattern. Builders are capable of creating and configuring objects or results that normally * take multiple steps to construct or are very complex to derive. *

*

* The builder interface defines a single method, {@link #get()}, that classes must implement. The result of this method should be the final configured object * or result after all building operations are performed. *

*

* It is a recommended practice that the methods supplied to configure the object or result being built return a reference to {@code this} so that method calls * can be chained together. *

* *

* Example Builder: *

* *
 * 
 * class FontBuilder implements Builder<Font> {
 *     private Font font;
 *
 *     public FontBuilder(String fontName) {
 *         this.font = new Font(fontName, Font.PLAIN, 12);
 *     }
 *
 *     public FontBuilder bold() {
 *         this.font = this.font.deriveFont(Font.BOLD);
 *         return this; // Reference returned so calls can be chained
 *     }
 *
 *     public FontBuilder size(float pointSize) {
 *         this.font = this.font.deriveFont(pointSize);
 *         return this; // Reference returned so calls can be chained
 *     }
 *
 *     // Other Font construction methods
 *
 *     public Font build() {
 *         return this.font;
 *     }
 * }
 * 
 * 
* * Example Builder Usage: * *
 * {@code
 * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF)
 *      .bold()
 *      .size(14.0f)
 *      .get();
 * }
 * 
* * * @param the type of object that the builder will construct or compute. * @since 1.0 * @see Supplier * @deprecated Use {@link Supplier}. */ @Deprecated public interface Builder extends Supplier { /** * Returns a reference to the object being constructed or result being calculated by the builder. * * @return The object constructed or result calculated by the builder. */ T build(); } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/CaseUtils.java000066400000000000000000000130461511432740600313170ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; /** * Case manipulation operations on Strings that contain words. * *

This class tries to handle {@code null} input gracefully. * An exception will not be thrown for a {@code null} input. * Each method documents its behavior in more detail.

* * @since 1.2 */ public class CaseUtils { /** * Converts all the delimiter separated words in a String into camelCase, * that is each word is made up of a title case character and then a series of * lowercase characters. * *

The delimiters represent a set of characters understood to separate words. * The first non-delimiter character after a delimiter will be capitalized. The first String * character may or may not be capitalized and it's determined by the user input for capitalizeFirstLetter * variable.

* *

A {@code null} input String returns {@code null}.

* *

A input string with only delimiter characters returns {@code ""}.

* * Capitalization uses the Unicode title case, normally equivalent to * upper case and cannot perform locale-sensitive mappings. * *
     * CaseUtils.toCamelCase(null, false)                                 = null
     * CaseUtils.toCamelCase("", false, *)                                = ""
     * CaseUtils.toCamelCase(*, false, null)                              = *
     * CaseUtils.toCamelCase(*, true, new char[0])                        = *
     * CaseUtils.toCamelCase("To.Camel.Case", false, new char[]{'.'})     = "toCamelCase"
     * CaseUtils.toCamelCase(" to @ Camel case", true, new char[]{'@'})   = "ToCamelCase"
     * CaseUtils.toCamelCase(" @to @ Camel case", false, new char[]{'@'}) = "toCamelCase"
     * CaseUtils.toCamelCase(" @", false, new char[]{'@'})                = ""
     * 
* * @param str the String to be converted to camelCase, may be null * @param capitalizeFirstLetter boolean that determines if the first character of first word should be title case. * @param delimiters set of characters to determine capitalization, null and/or empty array means whitespace * @return camelCase of String, {@code null} if null String input */ public static String toCamelCase(String str, final boolean capitalizeFirstLetter, final char... delimiters) { if (StringUtils.isEmpty(str)) { return str; } str = str.toLowerCase(); final int strLen = str.length(); final int[] newCodePoints = new int[strLen]; int outOffset = 0; final Set delimiterSet = toDelimiterSet(delimiters); boolean capitalizeNext = capitalizeFirstLetter; for (int index = 0; index < strLen;) { final int codePoint = str.codePointAt(index); if (delimiterSet.contains(codePoint)) { capitalizeNext = outOffset != 0; index += Character.charCount(codePoint); } else if (capitalizeNext || outOffset == 0 && capitalizeFirstLetter) { final int titleCaseCodePoint = Character.toTitleCase(codePoint); newCodePoints[outOffset++] = titleCaseCodePoint; index += Character.charCount(titleCaseCodePoint); capitalizeNext = false; } else { newCodePoints[outOffset++] = codePoint; index += Character.charCount(codePoint); } } return new String(newCodePoints, 0, outOffset); } /** * Converts an array of delimiters to a hash set of code points. Code point of space(32) is added * as the default value. The generated hash set provides O(1) lookup time. * * @param delimiters set of characters to determine capitalization, null means whitespace * @return Set */ private static Set toDelimiterSet(final char[] delimiters) { final Set delimiterHashSet = new HashSet<>(); delimiterHashSet.add(Character.codePointAt(new char[]{' '}, 0)); if (ArrayUtils.isEmpty(delimiters)) { return delimiterHashSet; } for (int index = 0; index < delimiters.length; index++) { delimiterHashSet.add(Character.codePointAt(delimiters, index)); } return delimiterHashSet; } /** * {@code CaseUtils} instances should NOT be constructed in * standard programming. Instead, the class should be used as * {@code CaseUtils.toCamelCase("foo bar", true, new char[]{'-'});}. * *

This constructor is public to permit tools that require a JavaBean * instance to operate.

*/ public CaseUtils() { } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/CharacterPredicate.java000066400000000000000000000023631511432740600331400ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; /** * A predicate for selecting code points. Implementations of this interface must be thread safe. * * @since 1.0 */ public interface CharacterPredicate { /** * Tests the code point with this predicate. * * @param codePoint the code point to test. * @return {@code true} if the code point matches the predicate, {@code false} otherwise. * @since 1.0 */ boolean test(int codePoint); } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/CharacterPredicates.java000066400000000000000000000061171511432740600333240ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; /** * Commonly used implementations of {@link CharacterPredicate}. Per the interface * requirements, all implementations are thread safe. * * @since 1.0 */ public enum CharacterPredicates implements CharacterPredicate { /** * Tests code points against {@link Character#isLetter(int)}. * * @since 1.0 */ LETTERS { @Override public boolean test(final int codePoint) { return Character.isLetter(codePoint); } }, /** * Tests code points against {@link Character#isDigit(int)}. * * @since 1.0 */ DIGITS { @Override public boolean test(final int codePoint) { return Character.isDigit(codePoint); } }, /** * Tests if the code points represents a number between 0 and 9. * * @since 1.2 */ ARABIC_NUMERALS { @Override public boolean test(final int codePoint) { return codePoint >= '0' && codePoint <= '9'; } }, /** * Tests if the code points represents a letter between a and z. * * @since 1.2 */ ASCII_LOWERCASE_LETTERS { @Override public boolean test(final int codePoint) { return codePoint >= 'a' && codePoint <= 'z'; } }, /** * Tests if the code points represents a letter between A and Z. * * @since 1.2 */ ASCII_UPPERCASE_LETTERS { @Override public boolean test(final int codePoint) { return codePoint >= 'A' && codePoint <= 'Z'; } }, /** * Tests if the code points represents a letter between a and Z. * * @since 1.2 */ ASCII_LETTERS { @Override public boolean test(final int codePoint) { return ASCII_LOWERCASE_LETTERS.test(codePoint) || ASCII_UPPERCASE_LETTERS.test(codePoint); } }, /** * Tests if the code points represents a letter between a and Z or a number between 0 and 9. * * @since 1.2 */ ASCII_ALPHA_NUMERALS { @Override public boolean test(final int codePoint) { return ASCII_LOWERCASE_LETTERS.test(codePoint) || ASCII_UPPERCASE_LETTERS.test(codePoint) || ARABIC_NUMERALS.test(codePoint); } } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/CompositeFormat.java000066400000000000000000000070641511432740600325410ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.text.FieldPosition; import java.text.Format; import java.text.ParseException; import java.text.ParsePosition; /** * Formats using one formatter and parses using a different formatter. An * example of use for this would be a webapp where data is taken in one way and * stored in a database another way. * * @since 1.0 */ public class CompositeFormat extends Format { /** * Required for serialization support. * * @see java.io.Serializable */ private static final long serialVersionUID = -4329119827877627683L; /** The parser to use. */ private final Format parser; /** The formatter to use. */ private final Format formatter; /** * Constructs a format that points its parseObject method to one implementation * and its format method to another. * * @param parser implementation. * @param formatter implementation. */ public CompositeFormat(final Format parser, final Format formatter) { this.parser = parser; this.formatter = formatter; } /** * Formats the input. * * @param obj the object to format. * @param toAppendTo the {@link StringBuffer} to append to. * @param pos the FieldPosition to use (or ignore). * @return {@code toAppendTo}. * @see Format#format(Object, StringBuffer, FieldPosition) */ @Override // Therefore has to use StringBuffer public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { return formatter.format(obj, toAppendTo, pos); } /** * Gets the parser Format implementation. * * @return formatter Format implementation */ public Format getFormatter() { return this.formatter; } /** * Gets the parser Format implementation. * * @return parser Format implementation */ public Format getParser() { return this.parser; } /** * Parses the input. * * @param source the String source. * @param pos the ParsePosition containing the position to parse from, will be updated according to parsing success (index) or failure (error index). * @return The parsed Object. * @see Format#parseObject(String, ParsePosition) */ @Override public Object parseObject(final String source, final ParsePosition pos) { return parser.parseObject(source, pos); } /** * Parses and then reformats a String. * * @param input String to reformat. * @return A reformatted String. * @throws ParseException thrown by parseObject(String) call. */ public String reformat(final String input) throws ParseException { return format(parseObject(input)); } } ExtendedMessageFormat.java000066400000000000000000000457361511432740600335750ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.text.Format; import java.text.MessageFormat; import java.text.ParsePosition; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Locale.Category; import java.util.Map; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.matcher.StringMatcherFactory; /** * Extends {@link java.text.MessageFormat} to allow pluggable/additional formatting * options for embedded format elements. Client code should specify a registry * of {@code FormatFactory} instances associated with {@code String} * format names. This registry will be consulted when the format elements are * parsed from the message pattern. In this way custom patterns can be specified, * and the formats supported by {@link java.text.MessageFormat} can be overridden * at the format and/or format style level (see MessageFormat). A "format element" * embedded in the message pattern is specified (()? signifies optionality):
* {@code {}argument-number({@code ,}format-name * ({@code ,}format-style)?)?{@code }} * *

* format-name and format-style values are trimmed of surrounding whitespace * in the manner of {@link java.text.MessageFormat}. If format-name denotes * {@code FormatFactory formatFactoryInstance} in {@code registry}, a {@code Format} * matching format-name and format-style is requested from * {@code formatFactoryInstance}. If this is successful, the {@code Format} * found is used for this format element. *

* *

NOTICE: The various subformat mutator methods are considered unnecessary; they exist on the parent * class to allow the type of customization which it is the job of this class to provide in * a configurable fashion. These methods have thus been disabled and will throw * {@code UnsupportedOperationException} if called. *

* *

Limitations inherited from {@link java.text.MessageFormat}:

*
    *
  • When using "choice" subformats, support for nested formatting instructions is limited * to that provided by the base class.
  • *
  • Thread-safety of {@code Format}s, including {@code MessageFormat} and thus * {@code ExtendedMessageFormat}, is not guaranteed.
  • *
* * @since 1.0 */ public class ExtendedMessageFormat extends MessageFormat { /** * Serializable Object. */ private static final long serialVersionUID = -2362048321261811743L; /** * The empty string. */ private static final String EMPTY_PATTERN = StringUtils.EMPTY; /** * A comma. */ private static final char START_FMT = ','; /** * A right curly bracket. */ private static final char END_FE = '}'; /** * A left curly bracket. */ private static final char START_FE = '{'; /** * A properly escaped character representing a single quote. */ private static final char QUOTE = '\''; /** * To pattern string. */ private String toPattern; /** * Our registry of FormatFactory. */ private final Map registry; /** * Constructs a new ExtendedMessageFormat for the default locale. * * @param pattern the pattern to use, not null. * @throws IllegalArgumentException in case of a bad pattern. */ public ExtendedMessageFormat(final String pattern) { this(pattern, Locale.getDefault(Category.FORMAT)); } /** * Constructs a new ExtendedMessageFormat. * * @param pattern the pattern to use, not null. * @param locale the locale to use, not null. * @throws IllegalArgumentException in case of a bad pattern. */ public ExtendedMessageFormat(final String pattern, final Locale locale) { this(pattern, locale, null); } /** * Constructs a new ExtendedMessageFormat. * * @param pattern the pattern to use, not null. * @param locale the locale to use, not null. * @param registry the registry of format factories, may be null. * @throws IllegalArgumentException in case of a bad pattern. */ public ExtendedMessageFormat(final String pattern, final Locale locale, final Map registry) { super(EMPTY_PATTERN); setLocale(locale); this.registry = registry != null ? Collections.unmodifiableMap(new HashMap<>(registry)) : null; applyPattern(pattern); } /** * Constructs a new ExtendedMessageFormat for the default locale. * * @param pattern the pattern to use, not null. * @param registry the registry of format factories, may be null. * @throws IllegalArgumentException in case of a bad pattern. */ public ExtendedMessageFormat(final String pattern, final Map registry) { this(pattern, Locale.getDefault(Category.FORMAT), registry); } /** * Consumes a quoted string, adding it to {@code appendTo} if specified. * * @param pattern pattern to parse. * @param pos current parse position. * @param appendTo optional StringBuilder to append. */ private void appendQuotedString(final String pattern, final ParsePosition pos, final StringBuilder appendTo) { assert pattern.toCharArray()[pos.getIndex()] == QUOTE : "Quoted string must start with quote character"; // handle quote character at the beginning of the string if (appendTo != null) { appendTo.append(QUOTE); } next(pos); final int start = pos.getIndex(); final char[] c = pattern.toCharArray(); for (int i = pos.getIndex(); i < pattern.length(); i++) { switch (c[pos.getIndex()]) { case QUOTE: next(pos); if (appendTo != null) { appendTo.append(c, start, pos.getIndex() - start); } return; default: next(pos); } } throw new IllegalArgumentException("Unterminated quoted string at position " + start); } /** * Applies the specified pattern. * * @param pattern String. */ @Override public final void applyPattern(final String pattern) { if (registry == null) { super.applyPattern(pattern); toPattern = super.toPattern(); return; } final ArrayList foundFormats = new ArrayList<>(); final ArrayList foundDescriptions = new ArrayList<>(); final StringBuilder stripCustom = new StringBuilder(pattern.length()); final ParsePosition pos = new ParsePosition(0); final char[] c = pattern.toCharArray(); int fmtCount = 0; while (pos.getIndex() < pattern.length()) { switch (c[pos.getIndex()]) { case QUOTE: appendQuotedString(pattern, pos, stripCustom); break; case START_FE: fmtCount++; seekNonWs(pattern, pos); final int start = pos.getIndex(); final int index = readArgumentIndex(pattern, next(pos)); stripCustom.append(START_FE).append(index); seekNonWs(pattern, pos); Format format = null; String formatDescription = null; if (c[pos.getIndex()] == START_FMT) { formatDescription = parseFormatDescription(pattern, next(pos)); format = getFormat(formatDescription); if (format == null) { stripCustom.append(START_FMT).append(formatDescription); } } foundFormats.add(format); foundDescriptions.add(format == null ? null : formatDescription); if (foundFormats.size() != fmtCount) { throw new IllegalArgumentException("The validated expression is false"); } if (foundDescriptions.size() != fmtCount) { throw new IllegalArgumentException("The validated expression is false"); } if (c[pos.getIndex()] != END_FE) { throw new IllegalArgumentException("Unreadable format element at position " + start); } //$FALL-THROUGH$ default: stripCustom.append(c[pos.getIndex()]); next(pos); } } super.applyPattern(stripCustom.toString()); toPattern = insertFormats(super.toPattern(), foundDescriptions); if (containsElements(foundFormats)) { final Format[] origFormats = getFormats(); // only loop over what we know we have, as MessageFormat on Java 1.3 // seems to provide an extra format element: int i = 0; for (final Format f : foundFormats) { if (f != null) { origFormats[i] = f; } i++; } super.setFormats(origFormats); } } /** * Tests whether the specified Collection contains non-null elements. * * @param coll to check. * @return {@code true} if some Object was found, {@code false} otherwise. */ private boolean containsElements(final Collection coll) { if (coll == null || coll.isEmpty()) { return false; } return coll.stream().anyMatch(Objects::nonNull); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof ExtendedMessageFormat)) { return false; } final ExtendedMessageFormat other = (ExtendedMessageFormat) obj; return Objects.equals(registry, other.registry) && Objects.equals(toPattern, other.toPattern); } /** * Gets a custom format from a format description. * * @param desc String. * @return Format. */ private Format getFormat(final String desc) { if (registry != null) { String name = desc; String args = null; final int i = desc.indexOf(START_FMT); if (i > 0) { name = desc.substring(0, i).trim(); args = desc.substring(i + 1).trim(); } final FormatFactory factory = registry.get(name); if (factory != null) { return factory.getFormat(name, args, getLocale()); } } return null; } /** * Consumes quoted string only. * * @param pattern pattern to parse. * @param pos current parse position. */ private void getQuotedString(final String pattern, final ParsePosition pos) { appendQuotedString(pattern, pos, null); } @Override public int hashCode() { final int prime = 31; final int result = super.hashCode(); return prime * result + Objects.hash(registry, toPattern); } /** * Inserts formats back into the pattern for toPattern() support. * * @param pattern source. * @param customPatterns The custom patterns to re-insert, if any. * @return full pattern. */ private String insertFormats(final String pattern, final ArrayList customPatterns) { if (!containsElements(customPatterns)) { return pattern; } final StringBuilder sb = new StringBuilder(pattern.length() * 2); final ParsePosition pos = new ParsePosition(0); int fe = -1; int depth = 0; while (pos.getIndex() < pattern.length()) { final char c = pattern.charAt(pos.getIndex()); switch (c) { case QUOTE: appendQuotedString(pattern, pos, sb); break; case START_FE: depth++; sb.append(START_FE).append(readArgumentIndex(pattern, next(pos))); // do not look for custom patterns when they are embedded, e.g. in a choice if (depth == 1) { fe++; final String customPattern = customPatterns.get(fe); if (customPattern != null) { sb.append(START_FMT).append(customPattern); } } break; case END_FE: depth--; //$FALL-THROUGH$ default: sb.append(c); next(pos); } } return sb.toString(); } /** * Advances parse position by 1. * * @param pos ParsePosition. * @return {@code pos}. */ private ParsePosition next(final ParsePosition pos) { pos.setIndex(pos.getIndex() + 1); return pos; } /** * Parses the format component of a format element. * * @param pattern string to parse. * @param pos current parse position. * @return Format description String. */ private String parseFormatDescription(final String pattern, final ParsePosition pos) { final int start = pos.getIndex(); seekNonWs(pattern, pos); final int text = pos.getIndex(); int depth = 1; while (pos.getIndex() < pattern.length()) { switch (pattern.charAt(pos.getIndex())) { case START_FE: depth++; next(pos); break; case END_FE: depth--; if (depth == 0) { return pattern.substring(text, pos.getIndex()); } next(pos); break; case QUOTE: getQuotedString(pattern, pos); break; default: next(pos); break; } } throw new IllegalArgumentException( "Unterminated format element at position " + start); } /** * Reads the argument index from the current format element. * * @param pattern pattern to parse. * @param pos current parse position. * @return argument index. */ private int readArgumentIndex(final String pattern, final ParsePosition pos) { final int start = pos.getIndex(); seekNonWs(pattern, pos); final StringBuilder result = new StringBuilder(); boolean error = false; for (; !error && pos.getIndex() < pattern.length(); next(pos)) { char c = pattern.charAt(pos.getIndex()); if (Character.isWhitespace(c)) { seekNonWs(pattern, pos); c = pattern.charAt(pos.getIndex()); if (c != START_FMT && c != END_FE) { error = true; continue; } } if ((c == START_FMT || c == END_FE) && result.length() > 0) { try { return Integer.parseInt(result.toString()); } catch (final NumberFormatException e) { // NOPMD // we've already ensured only digits, so unless something // outlandishly large was specified we should be okay. } } error = !Character.isDigit(c); result.append(c); } if (error) { throw new IllegalArgumentException( "Invalid format argument index at position " + start + ": " + pattern.substring(start, pos.getIndex())); } throw new IllegalArgumentException( "Unterminated format element at position " + start); } /** * Consumes whitespace from the current parse position. * * @param pattern String to read. * @param pos current position. */ private void seekNonWs(final String pattern, final ParsePosition pos) { int len = 0; final char[] buffer = pattern.toCharArray(); do { len = StringMatcherFactory.INSTANCE.splitMatcher().isMatch(buffer, pos.getIndex(), 0, buffer.length); pos.setIndex(pos.getIndex() + len); } while (len > 0 && pos.getIndex() < pattern.length()); } /** * Throws UnsupportedOperationException, see class Javadoc for details. * * @param formatElementIndex format element index. * @param newFormat the new format. * @throws UnsupportedOperationException always thrown since this isn't supported by {@link ExtendedMessageFormat}. */ @Override public void setFormat(final int formatElementIndex, final Format newFormat) { throw new UnsupportedOperationException(); } /** * Throws UnsupportedOperationException, see class Javadoc for details. * * @param argumentIndex argument index. * @param newFormat the new format. * @throws UnsupportedOperationException always thrown since this isn't supported by {@link ExtendedMessageFormat}. */ @Override public void setFormatByArgumentIndex(final int argumentIndex, final Format newFormat) { throw new UnsupportedOperationException(); } /** * Throws UnsupportedOperationException - see class Javadoc for details. * * @param newFormats new formats. * @throws UnsupportedOperationException always thrown since this isn't supported by {@link ExtendedMessageFormat}. */ @Override public void setFormats(final Format[] newFormats) { throw new UnsupportedOperationException(); } /** * Throws UnsupportedOperationException - see class Javadoc for details. * * @param newFormats new formats * @throws UnsupportedOperationException always thrown since this isn't supported by {@link ExtendedMessageFormat} */ @Override public void setFormatsByArgumentIndex(final Format[] newFormats) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public String toPattern() { return toPattern; } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/FormatFactory.java000066400000000000000000000026711511432740600322050ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.text.Format; import java.util.Locale; /** * Format factory. * * @since 1.0 */ @FunctionalInterface public interface FormatFactory { /** * Gets or creates a format instance. * * @param name The format type name. * @param arguments Arguments used to create the format instance. This allows the {@code FormatFactory} to implement the "format style" concept from * {@link java.text.MessageFormat}. * @param locale The locale, may be null. * @return The format instance. */ Format getFormat(String name, String arguments, Locale locale); } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/FormattableUtils.java000066400000000000000000000156731511432740600327140ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static java.util.FormattableFlags.LEFT_JUSTIFY; import java.util.Formattable; import java.util.Formatter; import org.apache.commons.lang3.StringUtils; /** * Provides utilities for working with the {@code Formattable} interface. * *

* The {@link Formattable} interface provides basic control over formatting when using a {@code Formatter}. It is primarily concerned with numeric precision and * padding, and is not designed to allow generalized alternate formats. *

* * @since 1.0 */ public class FormattableUtils { /** * A format that simply outputs the value as a string. */ private static final String SIMPLEST_FORMAT = "%s"; /** * Handles the common {@code Formattable} operations of truncate-pad-append, with no ellipsis on precision overflow, and padding width underflow with * spaces. * * @param seq the string to handle, not null. * @param formatter the destination formatter, not null. * @param flags the flags for formatting, see {@code Formattable}. * @param width the width of the output, see {@code Formattable}. * @param precision the precision of the output, see {@code Formattable}. * @return The {@code formatter} instance, not null. */ public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, final int precision) { return append(seq, formatter, flags, width, precision, ' ', null); } /** * Handles the common {@link Formattable} operations of truncate-pad-append, with no ellipsis on precision overflow. * * @param seq the string to handle, not null. * @param formatter the destination formatter, not null. * @param flags the flags for formatting, see {@code Formattable}. * @param width the width of the output, see {@code Formattable}. * @param precision the precision of the output, see {@code Formattable}. * @param padChar the pad character to use. * @return The {@code formatter} instance, not null. */ public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, final int precision, final char padChar) { return append(seq, formatter, flags, width, precision, padChar, null); } /** * Handles the common {@link Formattable} operations of truncate-pad-append. * * @param seq the string to handle, not null. * @param formatter the destination formatter, not null. * @param flags the flags for formatting, see {@code Formattable}. * @param width the width of the output, see {@code Formattable}. * @param precision the precision of the output, see {@code Formattable}. * @param padChar the pad character to use. * @param truncateEllipsis the ellipsis to use when precision dictates truncation, null or empty causes a hard truncation. * @return The {@code formatter} instance, not null. * @throws IllegalArgumentException if {@code ellipsis.length() > precision}, given that {@code ellipsis} is not null and {@code precision >= 0}. */ public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, final int precision, final char padChar, final CharSequence truncateEllipsis) { if (!(truncateEllipsis == null || precision < 0 || truncateEllipsis.length() <= precision)) { throw new IllegalArgumentException( String.format("Specified ellipsis '%s' exceeds precision of %s", truncateEllipsis, precision)); } final StringBuilder buf = new StringBuilder(seq); if (precision >= 0 && precision < seq.length()) { final CharSequence ellipsis; if (truncateEllipsis == null) { ellipsis = StringUtils.EMPTY; } else { ellipsis = truncateEllipsis; } buf.replace(precision - ellipsis.length(), seq.length(), ellipsis.toString()); } final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY; for (int i = buf.length(); i < width; i++) { buf.insert(leftJustify ? i : 0, padChar); } formatter.format(buf.toString()); return formatter; } /** * Handles the common {@link Formattable} operations of truncate-pad-append, padding width underflow with spaces. * * @param seq the string to handle, not null. * @param formatter the destination formatter, not null. * @param flags the flags for formatting, see {@code Formattable}. * @param width the width of the output, see {@code Formattable}. * @param precision the precision of the output, see {@code Formattable}. * @param ellipsis the ellipsis to use when precision dictates truncation, null or empty causes a hard truncation.. * @return The {@code formatter} instance, not null * @throws IllegalArgumentException if {@code ellipsis.length() > precision}, given that {@code ellipsis} is not null and {@code precision >= 0}. */ public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, final int precision, final CharSequence ellipsis) { return append(seq, formatter, flags, width, precision, ' ', ellipsis); } /** * Gets the default formatted representation of the specified {@code Formattable}. * * @param formattable the instance to convert to a string, not null. * @return The resulting string, not null. */ public static String toString(final Formattable formattable) { return String.format(SIMPLEST_FORMAT, formattable); } /** * {@code FormattableUtils} instances should NOT be constructed in standard programming. Instead, the methods of the class should be invoked statically. * *

* This constructor is public to permit tools that require a JavaBean instance to operate. *

*/ public FormattableUtils() { } } RandomStringGenerator.java000066400000000000000000000471711511432740600336300ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.IntUnaryOperator; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; /** * Generates random Unicode strings containing the specified number of code points. Instances are created using a builder class, which allows the callers to * define the properties of the generator. See the documentation for the {@link Builder} class to see available properties. * *
 * // Generates a 20 code point string, using only the letters a-z
 * RandomStringGenerator generator = RandomStringGenerator.builder().withinRange('a', 'z').build();
 * String randomLetters = generator.generate(20);
 * 
*
 * // Using Apache Commons RNG for randomness
 * UniformRandomProvider rng = RandomSource.create(...);
 * // Generates a 20 code point string, using only the letters a-z
 * RandomStringGenerator generator = RandomStringGenerator.builder()
 *     .withinRange('a', 'z')
 *     .usingRandom(rng::nextInt)
 *     .build();
 * String randomLetters = generator.generate(20);
 * 
*

* {@code RandomStringGenerator} instances are thread-safe when using the default random number generator (RNG). If a custom RNG is set by calling the method * {@link Builder#usingRandom(TextRandomProvider) Builder.usingRandom(TextRandomProvider)}, thread-safety must be ensured externally. *

* * @since 1.1 */ public final class RandomStringGenerator { /** * A builder for generating {@code RandomStringGenerator} instances. * *

* The behavior of a generator is controlled by properties set by this builder. Each property has a default value, which can be overridden by calling the * methods defined in this class, prior to calling {@link #build()}. *

*

* All the property setting methods return the {@code Builder} instance to allow for method chaining. *

*

* The minimum and maximum code point values are defined using {@link #withinRange(int, int)}. The default values are {@code 0} and * {@link Character#MAX_CODE_POINT} respectively. *

*

* The source of randomness can be set using {@link #usingRandom(TextRandomProvider)}, otherwise {@link ThreadLocalRandom} is used. *

*

* The type of code points returned can be filtered using {@link #filteredBy(CharacterPredicate...)}, which defines a collection of tests that are applied * to the randomly generated code points. The code points will only be included in the result if they pass at least one of the tests. Some commonly used * predicates are provided by the {@link CharacterPredicates} enum. *

*

* This class is not thread safe. *

* * @since 1.1 */ public static class Builder implements org.apache.commons.text.Builder { /** * The default maximum code point allowed: {@link Character#MAX_CODE_POINT} * ({@value}). */ public static final int DEFAULT_MAXIMUM_CODE_POINT = Character.MAX_CODE_POINT; /** * The default string length produced by this builder: {@value}. */ public static final int DEFAULT_LENGTH = 0; /** * The default minimum code point allowed: {@value}. */ public static final int DEFAULT_MINIMUM_CODE_POINT = 0; /** * The minimum code point allowed. */ private int minimumCodePoint = DEFAULT_MINIMUM_CODE_POINT; /** * The maximum code point allowed. */ private int maximumCodePoint = DEFAULT_MAXIMUM_CODE_POINT; /** * Filters for code points. */ private Set inclusivePredicates; /** * The source of randomness. */ private IntUnaryOperator random; /** * The source of provided characters. */ private Set characterSet = new HashSet<>(); /** * Whether calls accumulates the source of provided characters. The default is {@code false}. */ private boolean accumulate; /** * Creates a new instance. */ public Builder() { // empty } /** * Builds a new {@code RandomStringGenerator}. * * @return A new {@code RandomStringGenerator} * @deprecated Use {@link #get()}. */ @Deprecated @Override public RandomStringGenerator build() { return get(); } /** * Limits the characters in the generated string to those that match at least one of the predicates supplied. * *

* Passing {@code null} or an empty array to this method will revert to the default behavior of allowing any character. Multiple calls to this method * will replace the previously stored predicates. *

* * @param predicates the predicates, may be {@code null} or empty. * @return {@code this} instance. */ public Builder filteredBy(final CharacterPredicate... predicates) { if (ArrayUtils.isEmpty(predicates)) { inclusivePredicates = null; return this; } if (inclusivePredicates == null) { inclusivePredicates = new HashSet<>(); } else { inclusivePredicates.clear(); } Collections.addAll(inclusivePredicates, predicates); return this; } /** * Builds a new {@code RandomStringGenerator}. * * @return A new {@code RandomStringGenerator}. * @since 1.12.0 */ @Override public RandomStringGenerator get() { return new RandomStringGenerator(this); } private void initCharList() { if (!accumulate) { characterSet = new HashSet<>(); } } /** * Limits the characters in the generated string to those who match at supplied list of Character. * *

* Passing {@code null} or an empty array to this method will revert to the default behavior of allowing any character. Multiple calls to this method * will replace the previously stored Character. *

* * @param chars set of predefined Characters for random string generation the Character can be, may be {@code null} or empty. * @return {@code this} instance. * @since 1.2 */ public Builder selectFrom(final char... chars) { initCharList(); if (chars != null) { for (final char c : chars) { characterSet.add(c); } } return this; } /** * Sets whether calls accumulates the source of provided characters. The default is {@code false}. * *
         * {@code
         *     RandomStringGenerator gen = RandomStringGenerator.builder()
         *         .setAccumulate(true)
         *         .withinRange(new char[][] { { 'a', 'z' }, { 'A', 'Z' }, { '0', '9' } })
         *         .selectFrom('!', '"', '#', '$', '&', '\'', '(', ')', ',', '.', ':', ';', '?', '@', '[',
         *                     '\\', ']', '^', '_', '`', '{', '|', '}', '~') // punctuation
         *         // additional builder calls as needed
         *         .build();
         * }
         * 
* * @param accumulate whether calls accumulates the source of provided characters. The default is {@code false}. * @return {@code this} instance. * @since 1.14.0 */ public Builder setAccumulate(final boolean accumulate) { this.accumulate = accumulate; return this; } /** * Overrides the default source of randomness. It is highly recommended that a random number generator library like * Apache Commons RNG be used to provide the random number generation. * *

* {@link TextRandomProvider} is a functional interface and need not be explicitly implemented: *

* *
         * {@code
         *     UniformRandomProvider rng = RandomSource.create(...);
         *     RandomStringGenerator gen = RandomStringGenerator.builder()
         *         .usingRandom(rng::nextInt)
         *         // additional builder calls as needed
         *         .build();
         * }
         * 
* *

* Passing {@code null} to this method will revert to the default source of randomness. *

* * @param random the source of randomness, may be {@code null}. * @return {@code this} instance. * @since 1.14.0 */ public Builder usingRandom(final IntUnaryOperator random) { this.random = random; return this; } /** * Overrides the default source of randomness. It is highly recommended that a random number generator library like * Apache Commons RNG be used to provide the random number generation. * *

* {@link TextRandomProvider} is a functional interface and need not be explicitly implemented: *

* *
         * {@code
         *     UniformRandomProvider rng = RandomSource.create(...);
         *     RandomStringGenerator gen = RandomStringGenerator.builder()
         *         .usingRandom(rng::nextInt)
         *         // additional builder calls as needed
         *         .build();
         * }
         * 
* *

* Passing {@code null} to this method will revert to the default source of randomness. *

* * @param random the source of randomness, may be {@code null}. * @return {@code this} instance. */ public Builder usingRandom(final TextRandomProvider random) { this.random = random; return this; } /** * Sets the array of minimum and maximum char allowed in the generated string. * * For example: * *
         * {@code
         * char[][] pairs = { { '0', '9' } };
         * char[][] pairs = { { 'a', 'z' } };
         * char[][] pairs = { { 'a', 'z' }, { '0', '9' } };
         * }
         * 
* * @param pairs array of characters array, expected is to pass min, max pairs through this arg. * @return {@code this} instance. */ public Builder withinRange(final char[]... pairs) { initCharList(); if (pairs != null) { for (final char[] pair : pairs) { Validate.isTrue(pair.length == 2, "Each pair must contain minimum and maximum code point"); final int minimumCodePoint = pair[0]; final int maximumCodePoint = pair[1]; Validate.isTrue(minimumCodePoint <= maximumCodePoint, "Minimum code point %d is larger than maximum code point %d", minimumCodePoint, maximumCodePoint); for (int index = minimumCodePoint; index <= maximumCodePoint; index++) { characterSet.add((char) index); } } } return this; } /** * Sets the minimum and maximum code points allowed in the generated string. * * @param minimumCodePoint the smallest code point allowed (inclusive). * @param maximumCodePoint the largest code point allowed (inclusive). * @return {@code this} instance. * @throws IllegalArgumentException if {@code maximumCodePoint >} {@link Character#MAX_CODE_POINT}. * @throws IllegalArgumentException if {@code minimumCodePoint < 0}. * @throws IllegalArgumentException if {@code minimumCodePoint > maximumCodePoint}. */ public Builder withinRange(final int minimumCodePoint, final int maximumCodePoint) { Validate.isTrue(minimumCodePoint <= maximumCodePoint, "Minimum code point %d is larger than maximum code point %d", minimumCodePoint, maximumCodePoint); Validate.isTrue(minimumCodePoint >= 0, "Minimum code point %d is negative", minimumCodePoint); Validate.isTrue(maximumCodePoint <= Character.MAX_CODE_POINT, "Value %d is larger than Character.MAX_CODE_POINT.", maximumCodePoint); this.minimumCodePoint = minimumCodePoint; this.maximumCodePoint = maximumCodePoint; return this; } } /** * Constructs a new builder. * * @return a new builder. * @since 1.11.0 */ public static Builder builder() { return new Builder(); } /** * The smallest allowed code point (inclusive). */ private final int minimumCodePoint; /** * The largest allowed code point (inclusive). */ private final int maximumCodePoint; /** * Filters for code points. */ private final Set inclusivePredicates; /** * The source of randomness for this generator. */ private final IntUnaryOperator random; /** * The source of provided characters. */ private final List characterList; /** * Constructs the generator. * * @param minimumCodePoint smallest allowed code point (inclusive). * @param maximumCodePoint largest allowed code point (inclusive). * @param inclusivePredicates filters for code points. * @param random source of randomness. * @param characterSet list of predefined set of characters. */ private RandomStringGenerator(final Builder builder) { this.minimumCodePoint = builder.minimumCodePoint; this.maximumCodePoint = builder.maximumCodePoint; this.inclusivePredicates = builder.inclusivePredicates; this.random = builder.random; this.characterList = new ArrayList<>(builder.characterSet); } /** * Generates a random string, containing the specified number of code points. * *

* Code points are randomly selected between the minimum and maximum values defined in the generator. Surrogate and private use characters are not returned, * although the resulting string may contain pairs of surrogates that together encode a supplementary character. *

*

* Note: the number of {@code char} code units generated will exceed {@code length} if the string contains supplementary characters. See the * {@link Character} documentation to understand how Java stores Unicode values. *

* * @param length the number of code points to generate. * @return The generated string. * @throws IllegalArgumentException if {@code length < 0}. */ public String generate(final int length) { if (length == 0) { return StringUtils.EMPTY; } Validate.isTrue(length > 0, "Length %d is smaller than zero.", length); final StringBuilder builder = new StringBuilder(length); long remaining = length; do { final int codePoint; if (characterList != null && !characterList.isEmpty()) { codePoint = generateRandomNumber(characterList); } else { codePoint = generateRandomNumber(minimumCodePoint, maximumCodePoint); } switch (Character.getType(codePoint)) { case Character.UNASSIGNED: case Character.PRIVATE_USE: case Character.SURROGATE: continue; default: } if (inclusivePredicates != null) { boolean matchedFilter = false; for (final CharacterPredicate predicate : inclusivePredicates) { if (predicate.test(codePoint)) { matchedFilter = true; break; } } if (!matchedFilter) { continue; } } builder.appendCodePoint(codePoint); remaining--; } while (remaining != 0); return builder.toString(); } /** * Generates a random string, containing between the minimum (inclusive) and the maximum (inclusive) number of code points. * * @param minLengthInclusive the minimum (inclusive) number of code points to generate. * @param maxLengthInclusive the maximum (inclusive) number of code points to generate. * @return The generated string. * @throws IllegalArgumentException if {@code minLengthInclusive < 0}, or {@code maxLengthInclusive < minLengthInclusive}. * @see RandomStringGenerator#generate(int) * @since 1.2 */ public String generate(final int minLengthInclusive, final int maxLengthInclusive) { Validate.isTrue(minLengthInclusive >= 0, "Minimum length %d is smaller than zero.", minLengthInclusive); Validate.isTrue(minLengthInclusive <= maxLengthInclusive, "Maximum length %d is smaller than minimum length %d.", maxLengthInclusive, minLengthInclusive); return generate(generateRandomNumber(minLengthInclusive, maxLengthInclusive)); } /** * Generates a random number within a range, using a {@link ThreadLocalRandom} instance or the user-supplied source of randomness. * * @param minInclusive the minimum value allowed. * @param maxInclusive the maximum value allowed. * @return The random number. */ private int generateRandomNumber(final int minInclusive, final int maxInclusive) { if (random != null) { return random.applyAsInt(maxInclusive - minInclusive + 1) + minInclusive; } return ThreadLocalRandom.current().nextInt(minInclusive, maxInclusive + 1); } /** * Generates a random number within a range, using a {@link ThreadLocalRandom} instance or the user-supplied source of randomness. * * @param characterList predefined char list. * @return The random number. */ private int generateRandomNumber(final List characterList) { final int listSize = characterList.size(); if (random != null) { return String.valueOf(characterList.get(random.applyAsInt(listSize))).codePointAt(0); } return String.valueOf(characterList.get(ThreadLocalRandom.current().nextInt(0, listSize))).codePointAt(0); } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/StrBuilder.java000066400000000000000000003117171511432740600315100ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.io.IOException; import java.io.Reader; import java.io.Serializable; import java.io.Writer; import java.nio.CharBuffer; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; /** * Builds a string from constituent parts providing a more flexible and powerful API than {@link StringBuffer} and {@link StringBuilder}. *

* The main differences from {@link StrBuilder} and {@link StringBuilder} are: *

*
    *
  • Not synchronized
  • *
  • Not final
  • *
  • Subclasses have direct access to character array
  • *
  • Additional methods *
      *
    • appendWithSeparators - adds an array of values, with a separator
    • *
    • appendPadding - adds a length padding characters
    • *
    • appendFixedLength - adds a fixed width field to the builder
    • *
    • toCharArray/getChars - simpler ways to get a range of the character array
    • *
    • delete - delete char or string
    • *
    • replace - search and replace for a char or string
    • *
    • leftString/rightString/midString - substring without exceptions
    • *
    • contains - whether the builder contains a char or string
    • *
    • size/clear/isEmpty - collections style API methods
    • *
    *
  • *
  • Views *
      *
    • asTokenizer - uses the internal buffer as the source of a StrTokenizer
    • *
    • asReader - uses the internal buffer as the source of a Reader
    • *
    • asWriter - allows a Writer to write directly to the internal buffer
    • *
    *
  • *
*

* The aim has been to provide an API that mimics very closely what StringBuffer provides, but with additional methods. It should be noted that some edge cases, * with invalid indices or null input, have been altered - see individual methods. The biggest of these changes is that by default, null will not output the * text 'null'. This can be controlled by a property, {@link #setNullText(String)}. *

* * @since 1.0 * @deprecated Deprecated as of 1.3, use {@link TextStringBuilder} instead. This class will be removed in 2.0. */ @Deprecated public class StrBuilder implements CharSequence, Appendable, Serializable, Builder { /** * Inner class to allow StrBuilder to operate as a reader. */ final class StrBuilderReader extends Reader { /** The current stream position. */ private int pos; /** The last mark position. */ private int mark; /** * Default constructor. */ StrBuilderReader() { } /** {@inheritDoc} */ @Override public void close() { // do nothing } /** {@inheritDoc} */ @Override public void mark(final int readAheadLimit) { mark = pos; } /** {@inheritDoc} */ @Override public boolean markSupported() { return true; } /** {@inheritDoc} */ @Override public int read() { if (!ready()) { return -1; } return charAt(pos++); } /** {@inheritDoc} */ @Override public int read(final char[] b, final int off, int len) { if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) { throw new IndexOutOfBoundsException(); } if (len == 0) { return 0; } if (pos >= size()) { return -1; } if (pos + len > size()) { len = size() - pos; } StrBuilder.this.getChars(pos, pos + len, b, off); pos += len; return len; } /** {@inheritDoc} */ @Override public boolean ready() { return pos < size(); } /** {@inheritDoc} */ @Override public void reset() { pos = mark; } /** {@inheritDoc} */ @Override public long skip(long n) { if (pos + n > size()) { n = size() - pos; } if (n < 0) { return 0; } pos = Math.addExact(pos, Math.toIntExact(n)); return n; } } /** * Inner class to allow StrBuilder to operate as a tokenizer. */ final class StrBuilderTokenizer extends StrTokenizer { /** * Default constructor. */ StrBuilderTokenizer() { } /** {@inheritDoc} */ @Override public String getContent() { final String str = super.getContent(); if (str == null) { return StrBuilder.this.toString(); } return str; } /** {@inheritDoc} */ @Override protected List tokenize(final char[] chars, final int offset, final int count) { if (chars == null) { return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size()); } return super.tokenize(chars, offset, count); } } /** * Inner class to allow StrBuilder to operate as a writer. */ final class StrBuilderWriter extends Writer { /** * Default constructor. */ StrBuilderWriter() { } /** {@inheritDoc} */ @Override public void close() { // do nothing } /** {@inheritDoc} */ @Override public void flush() { // do nothing } /** {@inheritDoc} */ @Override public void write(final char[] cbuf) { StrBuilder.this.append(cbuf); } /** {@inheritDoc} */ @Override public void write(final char[] cbuf, final int off, final int len) { StrBuilder.this.append(cbuf, off, len); } /** {@inheritDoc} */ @Override public void write(final int c) { StrBuilder.this.append((char) c); } /** {@inheritDoc} */ @Override public void write(final String str) { StrBuilder.this.append(str); } /** {@inheritDoc} */ @Override public void write(final String str, final int off, final int len) { StrBuilder.this.append(str, off, len); } } /** * The extra capacity for new builders. */ static final int CAPACITY = 32; /** * Required for serialization support. * * @see java.io.Serializable */ private static final long serialVersionUID = 7628716375283629643L; /** Internal data storage. */ char[] buffer; // package-protected for test code use only /** Current size of the buffer. */ private int size; /** * The new line, {@code null} means use the system default from {@link System#lineSeparator()}. */ private String newLine; /** The null text. */ private String nullText; /** * Constructs an empty builder initial capacity 32 characters. */ public StrBuilder() { this(CAPACITY); } /** * Constructs an empty builder the specified initial capacity. * * @param initialCapacity the initial capacity, zero or less will be converted to 32. */ public StrBuilder(int initialCapacity) { if (initialCapacity <= 0) { initialCapacity = CAPACITY; } buffer = new char[initialCapacity]; } /** * Constructs a builder from the string, allocating 32 extra characters for growth. * * @param str the string to copy, null treated as blank string. */ public StrBuilder(final String str) { if (str == null) { buffer = new char[CAPACITY]; } else { buffer = new char[str.length() + CAPACITY]; append(str); } } /** * Appends a boolean value to the string builder. * * @param value the value to append. * @return {@code this} instance. */ public StrBuilder append(final boolean value) { if (value) { ensureCapacity(size + 4); buffer[size++] = 't'; buffer[size++] = 'r'; buffer[size++] = 'u'; } else { ensureCapacity(size + 5); buffer[size++] = 'f'; buffer[size++] = 'a'; buffer[size++] = 'l'; buffer[size++] = 's'; } buffer[size++] = 'e'; return this; } /** * Appends a char value to the string builder. * * @param ch the value to append. * @return {@code this} instance. */ @Override public StrBuilder append(final char ch) { final int len = length(); ensureCapacity(len + 1); buffer[size++] = ch; return this; } /** * Appends a char array to the string builder. Appending null will call {@link #appendNull()}. * * @param chars the char array to append. * @return {@code this} instance. */ public StrBuilder append(final char[] chars) { if (chars == null) { return appendNull(); } final int strLen = chars.length; if (strLen > 0) { final int len = length(); ensureCapacity(len + strLen); System.arraycopy(chars, 0, buffer, len, strLen); size += strLen; } return this; } /** * Appends a char array to the string builder. Appending null will call {@link #appendNull()}. * * @param chars the char array to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ public StrBuilder append(final char[] chars, final int startIndex, final int length) { if (chars == null) { return appendNull(); } if (startIndex < 0 || startIndex > chars.length) { throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length); } if (length < 0 || startIndex + length > chars.length) { throw new StringIndexOutOfBoundsException("Invalid length: " + length); } if (length > 0) { final int len = length(); ensureCapacity(len + length); System.arraycopy(chars, startIndex, buffer, len, length); size += length; } return this; } /** * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}. * * @param buf the char buffer to append. * @return {@code this} instance. */ public StrBuilder append(final CharBuffer buf) { if (buf == null) { return appendNull(); } if (buf.hasArray()) { final int length = buf.remaining(); final int len = length(); ensureCapacity(len + length); System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length); size += length; } else { append(buf.toString()); } return this; } /** * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}. * * @param buf the char buffer to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) { if (buf == null) { return appendNull(); } if (buf.hasArray()) { final int totalLength = buf.remaining(); if (startIndex < 0 || startIndex > totalLength) { throw new StringIndexOutOfBoundsException("startIndex must be valid"); } if (length < 0 || startIndex + length > totalLength) { throw new StringIndexOutOfBoundsException("length must be valid"); } final int len = length(); ensureCapacity(len + length); System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length); size += length; } else { append(buf.toString(), startIndex, length); } return this; } /** * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}. * * @param seq the CharSequence to append. * @return {@code this} instance. */ @Override public StrBuilder append(final CharSequence seq) { if (seq == null) { return appendNull(); } if (seq instanceof StrBuilder) { return append((StrBuilder) seq); } if (seq instanceof StringBuilder) { return append((StringBuilder) seq); } if (seq instanceof StringBuffer) { return append((StringBuffer) seq); } if (seq instanceof CharBuffer) { return append((CharBuffer) seq); } return append(seq.toString()); } /** * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}. * * @param seq the CharSequence to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ @Override public StrBuilder append(final CharSequence seq, final int startIndex, final int length) { if (seq == null) { return appendNull(); } return append(seq.toString(), startIndex, length); } /** * Appends a double value to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. */ public StrBuilder append(final double value) { return append(String.valueOf(value)); } /** * Appends a float value to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. */ public StrBuilder append(final float value) { return append(String.valueOf(value)); } /** * Appends an int value to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. */ public StrBuilder append(final int value) { return append(String.valueOf(value)); } /** * Appends a long value to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. */ public StrBuilder append(final long value) { return append(String.valueOf(value)); } /** * Appends an object to this string builder. Appending null will call {@link #appendNull()}. * * @param obj the object to append. * @return {@code this} instance. */ public StrBuilder append(final Object obj) { if (obj == null) { return appendNull(); } if (obj instanceof CharSequence) { return append((CharSequence) obj); } return append(obj.toString()); } /** * Appends another string builder to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string builder to append. * @return {@code this} instance. */ public StrBuilder append(final StrBuilder str) { if (str == null) { return appendNull(); } final int strLen = str.length(); if (strLen > 0) { final int len = length(); ensureCapacity(len + strLen); System.arraycopy(str.buffer, 0, buffer, len, strLen); size += strLen; } return this; } /** * Appends part of a string builder to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ public StrBuilder append(final StrBuilder str, final int startIndex, final int length) { if (str == null) { return appendNull(); } if (startIndex < 0 || startIndex > str.length()) { throw new StringIndexOutOfBoundsException("startIndex must be valid"); } if (length < 0 || startIndex + length > str.length()) { throw new StringIndexOutOfBoundsException("length must be valid"); } if (length > 0) { final int len = length(); ensureCapacity(len + length); str.getChars(startIndex, startIndex + length, buffer, len); size += length; } return this; } /** * Appends a string to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @return {@code this} instance. */ public StrBuilder append(final String str) { if (str == null) { return appendNull(); } final int strLen = str.length(); if (strLen > 0) { final int len = length(); ensureCapacity(len + strLen); str.getChars(0, strLen, buffer, len); size += strLen; } return this; } /** * Appends part of a string to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ public StrBuilder append(final String str, final int startIndex, final int length) { if (str == null) { return appendNull(); } if (startIndex < 0 || startIndex > str.length()) { throw new StringIndexOutOfBoundsException("startIndex must be valid"); } if (length < 0 || startIndex + length > str.length()) { throw new StringIndexOutOfBoundsException("length must be valid"); } if (length > 0) { final int len = length(); ensureCapacity(len + length); str.getChars(startIndex, startIndex + length, buffer, len); size += length; } return this; } /** * Calls {@link String#format(String, Object...)} and appends the result. * * @param format the format string. * @param objs the objects to use in the format string. * @return {@code this} to enable chaining. * @see String#format(String, Object...) */ public StrBuilder append(final String format, final Object... objs) { return append(String.format(format, objs)); } /** * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string buffer to append. * @return {@code this} instance. */ public StrBuilder append(final StringBuffer str) { if (str == null) { return appendNull(); } final int strLen = str.length(); if (strLen > 0) { final int len = length(); ensureCapacity(len + strLen); str.getChars(0, strLen, buffer, len); size += strLen; } return this; } /** * Appends part of a string buffer to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ public StrBuilder append(final StringBuffer str, final int startIndex, final int length) { if (str == null) { return appendNull(); } if (startIndex < 0 || startIndex > str.length()) { throw new StringIndexOutOfBoundsException("startIndex must be valid"); } if (length < 0 || startIndex + length > str.length()) { throw new StringIndexOutOfBoundsException("length must be valid"); } if (length > 0) { final int len = length(); ensureCapacity(len + length); str.getChars(startIndex, startIndex + length, buffer, len); size += length; } return this; } /** * Appends a StringBuilder to this string builder. Appending null will call {@link #appendNull()}. * * @param str the StringBuilder to append. * @return {@code this} instance. */ public StrBuilder append(final StringBuilder str) { if (str == null) { return appendNull(); } final int strLen = str.length(); if (strLen > 0) { final int len = length(); ensureCapacity(len + strLen); str.getChars(0, strLen, buffer, len); size += strLen; } return this; } /** * Appends part of a StringBuilder to this string builder. Appending null will call {@link #appendNull()}. * * @param str the StringBuilder to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. */ public StrBuilder append(final StringBuilder str, final int startIndex, final int length) { if (str == null) { return appendNull(); } if (startIndex < 0 || startIndex > str.length()) { throw new StringIndexOutOfBoundsException("startIndex must be valid"); } if (length < 0 || startIndex + length > str.length()) { throw new StringIndexOutOfBoundsException("length must be valid"); } if (length > 0) { final int len = length(); ensureCapacity(len + length); str.getChars(startIndex, startIndex + length, buffer, len); size += length; } return this; } /** * Appends each item in an iterable to the builder without any separators. Appending a null iterable will have no effect. Each object is appended using * {@link #append(Object)}. * * @param iterable the iterable to append. * @return {@code this} instance. */ public StrBuilder appendAll(final Iterable iterable) { if (iterable != null) { iterable.forEach(this::append); } return this; } /** * Appends each item in an iterator to the builder without any separators. Appending a null iterator will have no effect. Each object is appended using * {@link #append(Object)}. * * @param it the iterator to append. * @return {@code this} instance. */ public StrBuilder appendAll(final Iterator it) { if (it != null) { while (it.hasNext()) { append(it.next()); } } return this; } /** * Appends each item in an array to the builder without any separators. Appending a null array will have no effect. Each object is appended using * {@link #append(Object)}. * * @param the element type. * @param array the array to append. * @return {@code this} instance. */ public StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) { /* * @SuppressWarnings used to hide warning about vararg usage. We cannot use @SafeVarargs, since this method is not final. Using @SuppressWarnings is * fine, because it isn't inherited by subclasses, so each subclass must vouch for itself whether its use of 'array' is safe. */ if (array != null && array.length > 0) { for (final Object element : array) { append(element); } } return this; } /** * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the {@code int} value is used. If the formatted * value is larger than the length, the left hand side is lost. * * @param value the value to append. * @param width the fixed field width, zero or negative has no effect. * @param padChar the pad character to use. * @return {@code this} instance. */ public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) { return appendFixedWidthPadLeft(String.valueOf(value), width, padChar); } /** * Appends an object to the builder padding on the left to a fixed width. The {@code toString} of the object is used. If the object is larger than the * length, the left hand side is lost. If the object is null, the null text value is used. * * @param obj the object to append, null uses null text * @param width the fixed field width, zero or negative has no effect * @param padChar the pad character to use * @return {@code this} instance. */ public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) { if (width > 0) { ensureCapacity(size + width); String str = Objects.toString(obj, getNullText()); if (str == null) { str = StringUtils.EMPTY; } final int strLen = str.length(); if (strLen >= width) { str.getChars(strLen - width, strLen, buffer, size); } else { final int padLen = width - strLen; final int toIndex = size + padLen; Arrays.fill(buffer, size, toIndex, padChar); str.getChars(0, strLen, buffer, toIndex); } size += width; } return this; } /** * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the {@code int} value is used. If the object is * larger than the length, the right hand side is lost. * * @param value the value to append. * @param width the fixed field width, zero or negative has no effect. * @param padChar the pad character to use. * @return {@code this} instance. */ public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) { return appendFixedWidthPadRight(String.valueOf(value), width, padChar); } /** * Appends an object to the builder padding on the right to a fixed length. The {@code toString} of the object is used. If the object is larger than the * length, the right hand side is lost. If the object is null, null text value is used. * * @param obj the object to append, null uses null text. * @param width the fixed field width, zero or negative has no effect. * @param padChar the pad character to use. * @return {@code this} instance. */ public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) { if (width > 0) { ensureCapacity(size + width); String str = Objects.toString(obj, getNullText()); if (str == null) { str = StringUtils.EMPTY; } final int strLen = str.length(); if (strLen >= width) { str.getChars(0, width, buffer, size); } else { str.getChars(0, strLen, buffer, size); final int fromIndex = size + strLen; Arrays.fill(buffer, fromIndex, fromIndex + width - strLen, padChar); } size += width; } return this; } /** * Appends a boolean value followed by a {@link #appendNewLine() new line} to the string builder. * * @param value the value to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final boolean value) { return append(value).appendNewLine(); } /** * Appends a char value followed by a {@link #appendNewLine() new line} to the string builder. * * @param ch the value to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final char ch) { return append(ch).appendNewLine(); } /** * Appends a char array followed by a {@link #appendNewLine() new line} to the string builder. Appending null will call {@link #appendNull()}. * * @param chars the char array to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final char[] chars) { return append(chars).appendNewLine(); } /** * Appends a char array followed by a {@link #appendNewLine() new line} to the string builder. Appending null will call {@link #appendNull()}. * * @param chars the char array to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final char[] chars, final int startIndex, final int length) { return append(chars, startIndex, length).appendNewLine(); } /** * Appends a double value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final double value) { return append(value).appendNewLine(); } /** * Appends a float value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final float value) { return append(value).appendNewLine(); } /** * Appends an int value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final int value) { return append(value).appendNewLine(); } /** * Appends a long value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}. * * @param value the value to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final long value) { return append(value).appendNewLine(); } /** * Appends an object followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param obj the object to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final Object obj) { return append(obj).appendNewLine(); } /** * Appends another string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string builder to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final StrBuilder str) { return append(str).appendNewLine(); } /** * Appends part of a string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) { return append(str, startIndex, length).appendNewLine(); } /** * Appends a string followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final String str) { return append(str).appendNewLine(); } /** * Appends part of a string followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final String str, final int startIndex, final int length) { return append(str, startIndex, length).appendNewLine(); } /** * Calls {@link String#format(String, Object...)} and appends the result. * * @param format the format string. * @param objs the objects to use in the format string. * @return {@code this} to enable chaining. * @see String#format(String, Object...) * @see #appendNewLine() */ public StrBuilder appendln(final String format, final Object... objs) { return append(format, objs).appendNewLine(); } /** * Appends a string buffer followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string buffer to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final StringBuffer str) { return append(str).appendNewLine(); } /** * Appends part of a string buffer followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) { return append(str, startIndex, length).appendNewLine(); } /** * Appends a string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string builder to append. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final StringBuilder str) { return append(str).appendNewLine(); } /** * Appends part of a string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}. * * @param str the string builder to append. * @param startIndex the start index, inclusive, must be valid. * @param length the length to append, must be valid. * @return {@code this} instance. * @see #appendNewLine() */ public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) { return append(str, startIndex, length).appendNewLine(); } /** * Appends this builder's new line string to this builder. *

* By default, the new line is the system default from {@link System#lineSeparator()}. *

*

* The new line string can be changed using {@link #setNewLineText(String)}. For example, you can use this to force the output to always use Unix line * endings even when on Windows. *

* * @return {@code this} instance. * @see #getNewLineText() * @see #setNewLineText(String) */ public StrBuilder appendNewLine() { if (newLine == null) { append(System.lineSeparator()); return this; } return append(newLine); } /** * Appends this builder's null text to this builder. * * @return {@code this} instance. */ public StrBuilder appendNull() { if (nullText == null) { return this; } return append(nullText); } /** * Appends the pad character to the builder the specified number of times. * * @param length the length to append, negative means no append. * @param padChar the character to append. * @return {@code this} instance. */ public StrBuilder appendPadding(final int length, final char padChar) { if (length >= 0) { ensureCapacity(size + length); for (int i = 0; i < length; i++) { buffer[size++] = padChar; } } return this; } /** * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}. *

* This method is useful for adding a separator each time around the loop except the first. *

* *
     * for (Iterator it = list.iterator(); it.hasNext();) {
     *     appendSeparator(',');
     *     append(it.next());
     * }
     * 
*

* Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. *

* * @param separator the separator to use. * @return {@code this} instance. */ public StrBuilder appendSeparator(final char separator) { if (isNotEmpty()) { append(separator); } return this; } /** * Appends one of both separators to the builder If the builder is currently empty it will append the defaultIfEmpty-separator Otherwise it will append the * standard-separator * * The separator is appended using {@link #append(char)}. * * @param standard the separator if builder is not empty. * @param defaultIfEmpty the separator if builder is empty. * @return {@code this} instance. */ public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) { if (isNotEmpty()) { append(standard); } else { append(defaultIfEmpty); } return this; } /** * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using {@link #append(char)}. *

* This method is useful for adding a separator each time around the loop except the first. *

* *
     * for (int i = 0; i < list.size(); i++) {
     *     appendSeparator(",", i);
     *     append(list.get(i));
     * }
     * 
*

* Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. *

* * @param separator the separator to use. * @param loopIndex the loop index. * @return {@code this} instance. */ public StrBuilder appendSeparator(final char separator, final int loopIndex) { if (loopIndex > 0) { append(separator); } return this; } /** * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The separator is appended using * {@link #append(String)}. *

* This method is useful for adding a separator each time around the loop except the first. *

* *
     * for (Iterator it = list.iterator(); it.hasNext();) {
     *     appendSeparator(",");
     *     append(it.next());
     * }
     * 
*

* Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. *

* * @param separator the separator to use, null means no separator. * @return {@code this} instance. */ public StrBuilder appendSeparator(final String separator) { return appendSeparator(separator, null); } /** * Appends a separator to the builder if the loop index is greater than zero. Appending a null separator will have no effect. The separator is appended * using {@link #append(String)}. *

* This method is useful for adding a separator each time around the loop except the first. *

* *
     * for (int i = 0; i < list.size(); i++) {
     *     appendSeparator(",", i);
     *     append(list.get(i));
     * }
     * 
*

* Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. *

* * @param separator the separator to use, null means no separator. * @param loopIndex the loop index. * @return {@code this} instance. */ public StrBuilder appendSeparator(final String separator, final int loopIndex) { if (separator != null && loopIndex > 0) { append(separator); } return this; } /** * Appends one of both separators to the StrBuilder. If the builder is currently empty it will append the defaultIfEmpty-separator Otherwise it will append * the standard-separator *

* Appending a null separator will have no effect. The separator is appended using {@link #append(String)}. *

*

* This method is for example useful for constructing queries *

* *
     * StrBuilder whereClause = new StrBuilder();
     * if (searchCommand.getPriority() != null) {
     *   whereClause.appendSeparator(" and", " where");
     *   whereClause.append(" priority = ?")
     * }
     * if (searchCommand.getComponent() != null) {
     *   whereClause.appendSeparator(" and", " where");
     *   whereClause.append(" component = ?")
     * }
     * selectClause.append(whereClause)
     * 
* * @param standard the separator if builder is not empty, null means no separator. * @param defaultIfEmpty the separator if builder is empty, null means no separator. * @return {@code this} instance. */ public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) { final String str = isEmpty() ? defaultIfEmpty : standard; if (str != null) { append(str); } return this; } /** * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}. *

* This method tries to avoid doing any extra copies of contents. *

* * @param appendable the appendable to append data to. * @throws IOException if an I/O error occurs. * @see #readFrom(Readable) */ public void appendTo(final Appendable appendable) throws IOException { if (appendable instanceof Writer) { ((Writer) appendable).write(buffer, 0, size); } else if (appendable instanceof StringBuilder) { ((StringBuilder) appendable).append(buffer, 0, size); } else if (appendable instanceof StringBuffer) { ((StringBuffer) appendable).append(buffer, 0, size); } else if (appendable instanceof CharBuffer) { ((CharBuffer) appendable).put(buffer, 0, size); } else { appendable.append(this); } } /** * Appends an iterable placing separators between each value, but not before the first or after the last. Appending a null iterable will have no effect. * Each object is appended using {@link #append(Object)}. * * @param iterable the iterable to append. * @param separator the separator to use, null means no separator. * @return {@code this} instance. */ public StrBuilder appendWithSeparators(final Iterable iterable, final String separator) { if (iterable != null) { appendWithSeparators(iterable.iterator(), separator); } return this; } /** * Appends an iterator placing separators between each value, but not before the first or after the last. Appending a null iterator will have no effect. * Each object is appended using {@link #append(Object)}. * * @param iterator the iterator to append. * @param separator the separator to use, null means no separator. * @return {@code this} instance. */ public StrBuilder appendWithSeparators(final Iterator iterator, final String separator) { if (iterator != null) { final String sep = Objects.toString(separator, StringUtils.EMPTY); while (iterator.hasNext()) { append(iterator.next()); if (iterator.hasNext()) { append(sep); } } } return this; } /** * Appends an array placing separators between each value, but not before the first or after the last. Appending a null array will have no effect. Each * object is appended using {@link #append(Object)}. * * @param array the array to append. * @param separator the separator to use, null means no separator. * @return {@code this} instance. */ public StrBuilder appendWithSeparators(final Object[] array, final String separator) { if (array != null && array.length > 0) { final String sep = Objects.toString(separator, StringUtils.EMPTY); append(array[0]); for (int i = 1; i < array.length; i++) { append(sep); append(array[i]); } } return this; } /** * Gets the contents of this builder as a Reader. *

* This method allows the contents of the builder to be read using any standard method that expects a Reader. *

*

* To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away. *

*

* The internal character array is shared between the builder and the reader. This allows you to append to the builder after creating the reader, and the * changes will be picked up. Note however, that no synchronization occurs, so you must perform all operations with the builder and the reader in one * thread. *

*

* The returned reader supports marking, and ignores the flush method. *

* * @return a reader that reads from this builder. */ public Reader asReader() { return new StrBuilderReader(); } /** * Creates a tokenizer that can tokenize the contents of this builder. *

* This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to tokenize on space, tab, newline and form feed * (as per StringTokenizer). These values can be changed on the tokenizer class, before retrieving the tokens. *

*

* The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within certain limits, however there is no * synchronization. Once the tokenizer has been used once, it must be {@link StrTokenizer#reset() reset} to pickup the latest changes in the builder. For * example: *

* *
     * StrBuilder b = new StrBuilder();
     * b.append("a b ");
     * StrTokenizer t = b.asTokenizer();
     * String[] tokens1 = t.getTokenArray(); // returns a,b
     * b.append("c d ");
     * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
     * t.reset(); // reset causes builder changes to be picked up
     * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
     * 
*

* In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to alter how it tokenizes. Just remember * to call reset when you want to pickup builder changes. *

*

* Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])} with a non-null value will break the link with the builder. *

* * @return a tokenizer that is linked to this builder. */ public StrTokenizer asTokenizer() { return new StrBuilderTokenizer(); } /** * Gets this builder as a Writer that can be written to. *

* This method allows you to populate the contents of the builder using any standard method that takes a Writer. *

*

* To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is available at any time using the methods of the * {@code StrBuilder}. *

*

* The internal character array is shared between the builder and the writer. This allows you to intermix calls that append to the builder and write using * the writer and the changes will be occur correctly. Note however, that no synchronization occurs, so you must perform all operations with the builder and * the writer in one thread. *

*

* The returned writer ignores the close and flush methods. *

* * @return a writer that populates this builder. */ public Writer asWriter() { return new StrBuilderWriter(); } /** * Converts this instance to a String. * * @return This instance as a String. * @see #toString() * @deprecated Use {@link #get()}. */ @Deprecated @Override public String build() { return toString(); } /** * Gets the current size of the internal character array buffer. * * @return The capacity */ public int capacity() { return buffer.length; } /** * Gets the character at the specified index. * * @param index the index to retrieve, must be valid * @return The character at the index * @throws IndexOutOfBoundsException if the index is invalid * @see #setCharAt(int, char) * @see #deleteCharAt(int) */ @Override public char charAt(final int index) { if (index < 0 || index >= length()) { throw new StringIndexOutOfBoundsException(index); } return buffer[index]; } /** * Clears the string builder (convenience Collections API style method). *

* This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed by {@link #minimizeCapacity()}. *

*

* This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of Collections. *

* * @return {@code this} instance. */ public StrBuilder clear() { size = 0; return this; } /** * Checks if the string builder contains the specified char. * * @param ch the character to find. * @return true if the builder contains the character. */ public boolean contains(final char ch) { final char[] thisBuf = buffer; for (int i = 0; i < this.size; i++) { if (thisBuf[i] == ch) { return true; } } return false; } /** * Tests if the string builder contains the specified string. * * @param str the string to find. * @return true if the builder contains the string. */ public boolean contains(final String str) { return indexOf(str, 0) >= 0; } /** * Tests if the string builder contains a string matched using the specified matcher. *

* Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for the character 'a' followed by a number. *

* * @param matcher the matcher to use, null returns -1. * @return true if the matcher finds a match in the builder. */ public boolean contains(final StrMatcher matcher) { return indexOf(matcher, 0) >= 0; } /** * Deletes the characters between the two specified indices. * * @param startIndex the start index, inclusive, must be valid. * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder delete(final int startIndex, int endIndex) { endIndex = validateRange(startIndex, endIndex); final int len = endIndex - startIndex; if (len > 0) { deleteImpl(startIndex, endIndex, len); } return this; } /** * Deletes the character wherever it occurs in the builder. * * @param ch the character to delete. * @return {@code this} instance. */ public StrBuilder deleteAll(final char ch) { for (int i = 0; i < size; i++) { if (buffer[i] == ch) { final int start = i; while (++i < size) { if (buffer[i] != ch) { break; } } final int len = i - start; deleteImpl(start, i, len); i -= len; } } return this; } /** * Deletes the string wherever it occurs in the builder. * * @param str the string to delete, null causes no action. * @return {@code this} instance. */ public StrBuilder deleteAll(final String str) { final int len = str == null ? 0 : str.length(); if (len > 0) { int index = indexOf(str, 0); while (index >= 0) { deleteImpl(index, index + len, len); index = indexOf(str, index); } } return this; } /** * Deletes all parts of the builder that the matcher matches. *

* Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all occurrences where the character 'a' is * followed by a number. *

* * @param matcher the matcher to use to find the deletion, null causes no action. * @return {@code this} instance. */ public StrBuilder deleteAll(final StrMatcher matcher) { return replace(matcher, null, 0, size, -1); } /** * Deletes the character at the specified index. * * @param index the index to delete. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. * @see #charAt(int) * @see #setCharAt(int, char) */ public StrBuilder deleteCharAt(final int index) { if (index < 0 || index >= size) { throw new StringIndexOutOfBoundsException(index); } deleteImpl(index, index + 1, 1); return this; } /** * Deletes the character wherever it occurs in the builder. * * @param ch the character to delete. * @return {@code this} instance. */ public StrBuilder deleteFirst(final char ch) { for (int i = 0; i < size; i++) { if (buffer[i] == ch) { deleteImpl(i, i + 1, 1); break; } } return this; } /** * Deletes the string wherever it occurs in the builder. * * @param str the string to delete, null causes no action. * @return {@code this} instance. */ public StrBuilder deleteFirst(final String str) { final int len = str == null ? 0 : str.length(); if (len > 0) { final int index = indexOf(str, 0); if (index >= 0) { deleteImpl(index, index + len, len); } } return this; } /** * Deletes the first match within the builder using the specified matcher. *

* Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where the character 'a' is followed by a * number. *

* * @param matcher the matcher to use to find the deletion, null causes no action. * @return {@code this} instance. */ public StrBuilder deleteFirst(final StrMatcher matcher) { return replace(matcher, null, 0, size, 1); } /** * Internal method to delete a range without validation. * * @param startIndex the start index, must be valid. * @param endIndex the end index (exclusive), must be valid. * @param len the length, must be valid. * @throws IndexOutOfBoundsException if any index is invalid. */ private void deleteImpl(final int startIndex, final int endIndex, final int len) { System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); size -= len; } /** * Tests whether this builder ends with the specified string. *

* Note that this method handles null input quietly, unlike String. *

* * @param str the string to search for, null returns false. * @return true if the builder ends with the string. */ public boolean endsWith(final String str) { if (str == null) { return false; } final int len = str.length(); if (len == 0) { return true; } if (len > size) { return false; } int pos = size - len; for (int i = 0; i < len; i++, pos++) { if (buffer[pos] != str.charAt(i)) { return false; } } return true; } /** * Tests the capacity and ensures that it is at least the size specified. * * @param capacity the capacity to ensure. * @return {@code this} instance. */ public StrBuilder ensureCapacity(final int capacity) { if (capacity > buffer.length) { final char[] old = buffer; buffer = new char[capacity * 2]; System.arraycopy(old, 0, buffer, 0, size); } return this; } /** * Tests the contents of this builder against another to see if they contain the same character content. * * @param obj the object to check, null returns false. * @return true if the builders contain the same characters in the same order. */ @Override public boolean equals(final Object obj) { return obj instanceof StrBuilder && equals((StrBuilder) obj); } /** * Tests the contents of this builder against another to see if they contain the same character content. * * @param other the object to check, null returns false. * @return true if the builders contain the same characters in the same order. */ public boolean equals(final StrBuilder other) { if (this == other) { return true; } if (other == null) { return false; } if (this.size != other.size) { return false; } final char[] thisBuf = this.buffer; final char[] otherBuf = other.buffer; for (int i = size - 1; i >= 0; i--) { if (thisBuf[i] != otherBuf[i]) { return false; } } return true; } /** * Tests the contents of this builder against another to see if they contain the same character content ignoring case. * * @param other the object to check, null returns false. * @return true if the builders contain the same characters in the same order. */ public boolean equalsIgnoreCase(final StrBuilder other) { if (this == other) { return true; } if (this.size != other.size) { return false; } final char[] thisBuf = this.buffer; final char[] otherBuf = other.buffer; for (int i = size - 1; i >= 0; i--) { final char c1 = thisBuf[i]; final char c2 = otherBuf[i]; if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { return false; } } return true; } /** * Converts this instance to a String. * * @return This instance as a String. * @see #toString() * @since 1.12.0 */ @Override public String get() { return toString(); } /** * Copies the character array into the specified array. * * @param destination the destination array, null will cause an array to be created. * @return The input array, unless that was null or too small. */ public char[] getChars(char[] destination) { final int len = length(); if (destination == null || destination.length < len) { destination = new char[len]; } System.arraycopy(buffer, 0, destination, 0, len); return destination; } /** * Copies the character array into the specified array. * * @param startIndex first index to copy, inclusive, must be valid. * @param endIndex last index, exclusive, must be valid. * @param destination the destination array, must not be null or too small. * @param destinationIndex the index to start copying in destination. * @throws NullPointerException if the array is null. * @throws IndexOutOfBoundsException if any index is invalid. */ public void getChars(final int startIndex, final int endIndex, final char[] destination, final int destinationIndex) { if (startIndex < 0) { throw new StringIndexOutOfBoundsException(startIndex); } if (endIndex < 0 || endIndex > length()) { throw new StringIndexOutOfBoundsException(endIndex); } if (startIndex > endIndex) { throw new StringIndexOutOfBoundsException("end < start"); } System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex); } /** * Gets the text to be appended when a {@link #appendNewLine() new line} is added. * * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}. */ public String getNewLineText() { return newLine; } /** * Gets the text to be appended when null is added. * * @return The null text, null means no append. */ public String getNullText() { return nullText; } /** * Gets a suitable hash code for this builder. * * @return a hash code. */ @Override public int hashCode() { final char[] buf = buffer; int hash = 0; for (int i = size - 1; i >= 0; i--) { hash = 31 * hash + buf[i]; } return hash; } /** * Searches the string builder to find the first reference to the specified char. * * @param ch the character to find. * @return The first index of the character, or -1 if not found. */ public int indexOf(final char ch) { return indexOf(ch, 0); } /** * Searches the string builder to find the first reference to the specified char. * * @param ch the character to find. * @param startIndex the index to start at, invalid index rounded to edge. * @return The first index of the character, or -1 if not found. */ public int indexOf(final char ch, int startIndex) { startIndex = Math.max(startIndex, 0); if (startIndex >= size) { return -1; } final char[] thisBuf = buffer; for (int i = startIndex; i < size; i++) { if (thisBuf[i] == ch) { return i; } } return -1; } /** * Searches the string builder to find the first reference to the specified string. *

* Note that a null input string will return -1, whereas the JDK throws an exception. *

* * @param str the string to find, null returns -1. * @return The first index of the string, or -1 if not found. */ public int indexOf(final String str) { return indexOf(str, 0); } /** * Searches the string builder to find the first reference to the specified string starting searching from the given index. *

* Note that a null input string will return -1, whereas the JDK throws an exception. *

* * @param str the string to find, null returns -1. * @param startIndex the index to start at, invalid index rounded to edge. * @return The first index of the string, or -1 if not found. */ public int indexOf(final String str, int startIndex) { startIndex = Math.max(0, startIndex); if (str == null || startIndex >= size) { return StringUtils.INDEX_NOT_FOUND; } final int strLen = str.length(); if (strLen == 1) { return indexOf(str.charAt(0), startIndex); } if (strLen == 0) { return startIndex; } if (strLen > size) { return StringUtils.INDEX_NOT_FOUND; } final char[] thisBuf = buffer; final int searchLen = size - strLen + 1; for (int i = startIndex; i < searchLen; i++) { boolean found = true; for (int j = 0; j < strLen && found; j++) { found = str.charAt(j) == thisBuf[i + j]; } if (found) { return i; } } return StringUtils.INDEX_NOT_FOUND; } /** * Searches the string builder using the matcher to find the first match. *

* Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the character 'a' followed by a number. *

* * @param matcher the matcher to use, null returns -1. * @return The first index matched, or -1 if not found. */ public int indexOf(final StrMatcher matcher) { return indexOf(matcher, 0); } /** * Searches the string builder using the matcher to find the first match searching from the given index. *

* Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the character 'a' followed by a number. *

* * @param matcher the matcher to use, null returns -1. * @param startIndex the index to start at, invalid index rounded to edge. * @return The first index matched, or -1 if not found. */ public int indexOf(final StrMatcher matcher, int startIndex) { startIndex = Math.max(startIndex, 0); if (matcher == null || startIndex >= size) { return -1; } final int len = size; final char[] buf = buffer; for (int i = startIndex; i < len; i++) { if (matcher.isMatch(buf, i, startIndex, len) > 0) { return i; } } return -1; } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid. * @param value the value to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(int index, final boolean value) { validateIndex(index); if (value) { ensureCapacity(size + 4); System.arraycopy(buffer, index, buffer, index + 4, size - index); buffer[index++] = 't'; buffer[index++] = 'r'; buffer[index++] = 'u'; buffer[index] = 'e'; size += 4; } else { ensureCapacity(size + 5); System.arraycopy(buffer, index, buffer, index + 5, size - index); buffer[index++] = 'f'; buffer[index++] = 'a'; buffer[index++] = 'l'; buffer[index++] = 's'; buffer[index] = 'e'; size += 5; } return this; } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid. * @param value the value to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final char value) { validateIndex(index); ensureCapacity(size + 1); System.arraycopy(buffer, index, buffer, index + 1, size - index); buffer[index] = value; size++; return this; } /** * Inserts the character array into this builder. Inserting null will use the stored null text value. * * @param index the index to add at, must be valid. * @param chars the char array to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final char[] chars) { validateIndex(index); if (chars == null) { return insert(index, nullText); } final int len = chars.length; if (len > 0) { ensureCapacity(size + len); System.arraycopy(buffer, index, buffer, index + len, size - index); System.arraycopy(chars, 0, buffer, index, len); size += len; } return this; } /** * Inserts part of the character array into this builder. Inserting null will use the stored null text value. * * @param index the index to add at, must be valid. * @param chars the char array to insert. * @param offset the offset into the character array to start at, must be valid. * @param length the length of the character array part to copy, must be positive. * @return {@code this} instance. * @throws IndexOutOfBoundsException if any index is invalid. */ public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) { validateIndex(index); if (chars == null) { return insert(index, nullText); } if (offset < 0 || offset > chars.length) { throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); } if (length < 0 || offset + length > chars.length) { throw new StringIndexOutOfBoundsException("Invalid length: " + length); } if (length > 0) { ensureCapacity(size + length); System.arraycopy(buffer, index, buffer, index + length, size - index); System.arraycopy(chars, offset, buffer, index, length); size += length; } return this; } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid. * @param value the value to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final double value) { return insert(index, String.valueOf(value)); } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid. * @param value the value to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final float value) { return insert(index, String.valueOf(value)); } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid. * @param value the value to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final int value) { return insert(index, String.valueOf(value)); } /** * Inserts the value into this builder. * * @param index the index to add at, must be valid. * @param value the value to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final long value) { return insert(index, String.valueOf(value)); } /** * Inserts the string representation of an object into this builder. Inserting null will use the stored null text value. * * @param index the index to add at, must be valid. * @param obj the object to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, final Object obj) { if (obj == null) { return insert(index, nullText); } return insert(index, obj.toString()); } /** * Inserts the string into this builder. Inserting null will use the stored null text value. * * @param index the index to add at, must be valid. * @param str the string to insert. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder insert(final int index, String str) { validateIndex(index); if (str == null) { str = nullText; } if (str != null) { final int strLen = str.length(); if (strLen > 0) { final int newSize = size + strLen; ensureCapacity(newSize); System.arraycopy(buffer, index, buffer, index + strLen, size - index); size = newSize; str.getChars(0, strLen, buffer, index); } } return this; } /** * Tests if the string builder is empty (convenience Collections API style method). *

* This method is the same as checking {@link #length()} and is provided to match the API of Collections. *

* * @return {@code true} if the size is {@code 0}. */ public boolean isEmpty() { return size == 0; } /** * Tests if the string builder is not empty (convenience Collections API style method). *

* This method is the same as checking {@link #length()} and is provided to match the API of Collections. *

* * @return {@code true} if the size is greater than {@code 0}. * @since 1.10.0 */ public boolean isNotEmpty() { return size > 0; } /** * Searches the string builder to find the last reference to the specified char. * * @param ch the character to find. * @return The last index of the character, or -1 if not found. */ public int lastIndexOf(final char ch) { return lastIndexOf(ch, size - 1); } /** * Searches the string builder to find the last reference to the specified char. * * @param ch the character to find. * @param startIndex the index to start at, invalid index rounded to edge. * @return The last index of the character, or -1 if not found. */ public int lastIndexOf(final char ch, int startIndex) { startIndex = startIndex >= size ? size - 1 : startIndex; if (startIndex < 0) { return -1; } for (int i = startIndex; i >= 0; i--) { if (buffer[i] == ch) { return i; } } return -1; } /** * Searches the string builder to find the last reference to the specified string. *

* Note that a null input string will return -1, whereas the JDK throws an exception. *

* * @param str the string to find, null returns -1. * @return The last index of the string, or -1 if not found. */ public int lastIndexOf(final String str) { return lastIndexOf(str, size - 1); } /** * Searches the string builder to find the last reference to the specified string starting searching from the given index. *

* Note that a null input string will return -1, whereas the JDK throws an exception. *

* * @param str the string to find, null returns -1. * @param startIndex the index to start at, invalid index rounded to edge. * @return The last index of the string, or -1 if not found. */ public int lastIndexOf(final String str, int startIndex) { startIndex = startIndex >= size ? size - 1 : startIndex; if (str == null || startIndex < 0) { return StringUtils.INDEX_NOT_FOUND; } final int strLen = str.length(); if (strLen == 0) { return startIndex; } if (strLen > size) { return StringUtils.INDEX_NOT_FOUND; } if (strLen == 1) { return lastIndexOf(str.charAt(0), startIndex); } for (int i = startIndex - strLen + 1; i >= 0; i--) { boolean found = true; for (int j = 0; j < strLen && found; j++) { found = str.charAt(j) == buffer[i + j]; } if (found) { return i; } } return StringUtils.INDEX_NOT_FOUND; } /** * Searches the string builder using the matcher to find the last match. *

* Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the character 'a' followed by a number. *

* * @param matcher the matcher to use, null returns -1. * @return The last index matched, or -1 if not found. */ public int lastIndexOf(final StrMatcher matcher) { return lastIndexOf(matcher, size); } /** * Searches the string builder using the matcher to find the last match searching from the given index. *

* Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the character 'a' followed by a number. *

* * @param matcher the matcher to use, null returns -1. * @param startIndex the index to start at, invalid index rounded to edge. * @return The last index matched, or -1 if not found. */ public int lastIndexOf(final StrMatcher matcher, int startIndex) { startIndex = startIndex >= size ? size - 1 : startIndex; if (matcher == null || startIndex < 0) { return -1; } final char[] buf = buffer; final int endIndex = startIndex + 1; for (int i = startIndex; i >= 0; i--) { if (matcher.isMatch(buf, i, 0, endIndex) > 0) { return i; } } return -1; } /** * Extracts the leftmost characters from the string builder without throwing an exception. *

* This method extracts the left {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus * the returned string may be shorter than the length requested. *

* * @param length the number of characters to extract, negative returns empty string. * @return The new string. */ public String leftString(final int length) { if (length <= 0) { return StringUtils.EMPTY; } if (length >= size) { return new String(buffer, 0, size); } return new String(buffer, 0, length); } /** * Gets the length of the string builder. * * @return The length */ @Override public int length() { return size; } /** * Extracts some characters from the middle of the string builder without throwing an exception. *

* This method extracts {@code length} characters from the builder at the specified index. If the index is negative it is treated as zero. If the index is * greater than the builder size, it is treated as the builder size. If the length is negative, the empty string is returned. If insufficient characters are * available in the builder, as much as possible is returned. Thus the returned string may be shorter than the length requested. *

* * @param index the index to start at, negative means zero. * @param length the number of characters to extract, negative returns empty string. * @return The new string. */ public String midString(int index, final int length) { if (index < 0) { index = 0; } if (length <= 0 || index >= size) { return StringUtils.EMPTY; } if (size <= index + length) { return new String(buffer, index, size - index); } return new String(buffer, index, length); } /** * Minimizes the capacity to the actual length of the string. * * @return {@code this} instance. */ public StrBuilder minimizeCapacity() { if (buffer.length > length()) { final char[] old = buffer; buffer = new char[length()]; System.arraycopy(old, 0, buffer, 0, size); } return this; } /** * If possible, reads chars from the provided {@link Readable} directly into underlying character buffer without making extra copies. * * @param readable object to read from. * @return The number of characters read. * @throws IOException if an I/O error occurs. * @see #appendTo(Appendable) */ public int readFrom(final Readable readable) throws IOException { final int oldSize = size; if (readable instanceof Reader) { final Reader r = (Reader) readable; ensureCapacity(size + 1); int read; while ((read = r.read(buffer, size, buffer.length - size)) != -1) { size += read; ensureCapacity(size + 1); } } else if (readable instanceof CharBuffer) { final CharBuffer cb = (CharBuffer) readable; final int remaining = cb.remaining(); ensureCapacity(size + remaining); cb.get(buffer, size, remaining); size += remaining; } else { while (true) { ensureCapacity(size + 1); final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); final int read = readable.read(buf); if (read == -1) { break; } size += read; } } return size - oldSize; } /** * Replaces a portion of the string builder with another string. The length of the inserted string does not have to match the removed length. * * @param startIndex the start index, inclusive, must be valid. * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string. * @param replaceStr the string to replace with, null means delete range. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. */ public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) { endIndex = validateRange(startIndex, endIndex); final int insertLen = replaceStr == null ? 0 : replaceStr.length(); replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); return this; } /** * Advanced search and replaces within the builder using a matcher. *

* Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all occurrences where the character 'a' is followed by * a number. *

* * @param matcher the matcher to use to find the deletion, null causes no action. * @param replaceStr the string to replace the match with, null is a delete. * @param startIndex the start index, inclusive, must be valid. * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string. * @param replaceCount the number of times to replace, -1 for replace all. * @return {@code this} instance. * @throws IndexOutOfBoundsException if start index is invalid. */ public StrBuilder replace(final StrMatcher matcher, final String replaceStr, final int startIndex, int endIndex, final int replaceCount) { endIndex = validateRange(startIndex, endIndex); return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); } /** * Replaces the search character with the replace character throughout the builder. * * @param search the search character. * @param replace the replace character. * @return {@code this} instance. */ public StrBuilder replaceAll(final char search, final char replace) { if (search != replace) { for (int i = 0; i < size; i++) { if (buffer[i] == search) { buffer[i] = replace; } } } return this; } /** * Replaces the search string with the replace string throughout the builder. * * @param searchStr the search string, null causes no action to occur. * @param replaceStr the replace string, null is equivalent to an empty string. * @return {@code this} instance. */ public StrBuilder replaceAll(final String searchStr, final String replaceStr) { final int searchLen = searchStr == null ? 0 : searchStr.length(); if (searchLen > 0) { final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); int index = indexOf(searchStr, 0); while (index >= 0) { replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); index = indexOf(searchStr, index + replaceLen); } } return this; } /** * Replaces all matches within the builder with the replace string. *

* Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all occurrences where the character 'a' is * followed by a number. *

* * @param matcher the matcher to use to find the deletion, null causes no action. * @param replaceStr the replace string, null is equivalent to an empty string. * @return {@code this} instance. */ public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) { return replace(matcher, replaceStr, 0, size, -1); } /** * Replaces the first instance of the search character with the replace character in the builder. * * @param search the search character. * @param replace the replace character. * @return {@code this} instance. */ public StrBuilder replaceFirst(final char search, final char replace) { if (search != replace) { for (int i = 0; i < size; i++) { if (buffer[i] == search) { buffer[i] = replace; break; } } } return this; } /** * Replaces the first instance of the search string with the replace string. * * @param searchStr the search string, null causes no action to occur. * @param replaceStr the replace string, null is equivalent to an empty string. * @return {@code this} instance. */ public StrBuilder replaceFirst(final String searchStr, final String replaceStr) { final int searchLen = searchStr == null ? 0 : searchStr.length(); if (searchLen > 0) { final int index = indexOf(searchStr, 0); if (index >= 0) { final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); } } return this; } /** * Replaces the first match within the builder with the replace string. *

* Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where the character 'a' is followed by a * number. *

* * @param matcher the matcher to use to find the deletion, null causes no action. * @param replaceStr the replace string, null is equivalent to an empty string. * @return {@code this} instance. */ public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) { return replace(matcher, replaceStr, 0, size, 1); } /** * Internal method to delete a range without validation. * * @param startIndex the start index, must be valid. * @param endIndex the end index (exclusive), must be valid. * @param removeLen the length to remove (endIndex - startIndex), must be valid. * @param insertStr the string to replace with, null means delete range. * @param insertLen the length of the insert string, must be valid. * @throws IndexOutOfBoundsException if any index is invalid. */ private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) { final int newSize = size - removeLen + insertLen; if (insertLen != removeLen) { ensureCapacity(newSize); System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); size = newSize; } if (insertLen > 0) { insertStr.getChars(0, insertLen, buffer, startIndex); } } /** * Replaces within the builder using a matcher. *

* Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all occurrences where the character 'a' is followed by * a number. *

* * @param matcher the matcher to use to find the deletion, null causes no action. * @param replaceStr the string to replace the match with, null is a delete. * @param from the start index, must be valid. * @param to the end index (exclusive), must be valid. * @param replaceCount the number of times to replace, -1 for replace all. * @return {@code this} instance. * @throws IndexOutOfBoundsException if any index is invalid. */ private StrBuilder replaceImpl(final StrMatcher matcher, final String replaceStr, final int from, int to, int replaceCount) { if (matcher == null || size == 0) { return this; } final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); for (int i = from; i < to && replaceCount != 0; i++) { final char[] buf = buffer; final int removeLen = matcher.isMatch(buf, i, from, to); if (removeLen > 0) { replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); to = to - removeLen + replaceLen; i = i + replaceLen - 1; if (replaceCount > 0) { replaceCount--; } } } return this; } /** * Reverses the string builder placing each character in the opposite index. * * @return {@code this} instance. */ public StrBuilder reverse() { if (size == 0) { return this; } final int half = size / 2; final char[] buf = buffer; for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) { final char swap = buf[leftIdx]; buf[leftIdx] = buf[rightIdx]; buf[rightIdx] = swap; } return this; } /** * Extracts the rightmost characters from the string builder without throwing an exception. *

* This method extracts the right {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus * the returned string may be shorter than the length requested. *

* * @param length the number of characters to extract, negative returns empty string. * @return The new string. */ public String rightString(final int length) { if (length <= 0) { return StringUtils.EMPTY; } if (length >= size) { return new String(buffer, 0, size); } return new String(buffer, size - length, length); } /** * Sets the character at the specified index. * * @param index the index to set. * @param ch the new character. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the index is invalid. * @see #charAt(int) * @see #deleteCharAt(int) */ public StrBuilder setCharAt(final int index, final char ch) { if (index < 0 || index >= length()) { throw new StringIndexOutOfBoundsException(index); } buffer[index] = ch; return this; } /** * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero. * * @param length the length to set to, must be zero or positive. * @return {@code this} instance. * @throws IndexOutOfBoundsException if the length is negative. */ public StrBuilder setLength(final int length) { if (length < 0) { throw new StringIndexOutOfBoundsException(length); } if (length < size) { size = length; } else if (length > size) { ensureCapacity(length); Arrays.fill(buffer, size, length, CharUtils.NUL); size = length; } return this; } /** * Sets the text to be appended when {@link #appendNewLine() new line} is called. * * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}. * @return {@code this} instance. */ public StrBuilder setNewLineText(final String newLine) { this.newLine = newLine; return this; } /** * Sets the text to be appended when null is added. * * @param nullText the null text, null means no append. * @return {@code this} instance. */ public StrBuilder setNullText(String nullText) { if (nullText != null && nullText.isEmpty()) { nullText = null; } this.nullText = nullText; return this; } /** * Gets the length of the string builder. *

* This method is the same as {@link #length()} and is provided to match the API of Collections. *

* * @return The length. */ public int size() { return size; } /** * Checks whether this builder starts with the specified string. *

* Note that this method handles null input quietly, unlike String. *

* * @param str the string to search for, null returns false. * @return true if the builder starts with the string. */ public boolean startsWith(final String str) { if (str == null) { return false; } final int len = str.length(); if (len == 0) { return true; } if (len > size) { return false; } for (int i = 0; i < len; i++) { if (buffer[i] != str.charAt(i)) { return false; } } return true; } /** * {@inheritDoc} */ @Override public CharSequence subSequence(final int startIndex, final int endIndex) { if (startIndex < 0) { throw new StringIndexOutOfBoundsException(startIndex); } if (endIndex > size) { throw new StringIndexOutOfBoundsException(endIndex); } if (startIndex > endIndex) { throw new StringIndexOutOfBoundsException(endIndex - startIndex); } return substring(startIndex, endIndex); } /** * Extracts a portion of this string builder as a string. * * @param start the start index, inclusive, must be valid. * @return The new string. * @throws IndexOutOfBoundsException if the index is invalid. */ public String substring(final int start) { return substring(start, size); } /** * Extracts a portion of this string builder as a string. *

* Note: This method treats an endIndex greater than the length of the builder as equal to the length of the builder, and continues without error, unlike * StringBuffer or String. * * @param startIndex the start index, inclusive, must be valid. * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string. * @return The new string. * @throws IndexOutOfBoundsException if the index is invalid. */ public String substring(final int startIndex, int endIndex) { endIndex = validateRange(startIndex, endIndex); return new String(buffer, startIndex, endIndex - startIndex); } /** * Copies the builder's character array into a new character array. * * @return a new array that represents the contents of the builder. */ public char[] toCharArray() { return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size); } /** * Copies part of the builder's character array into a new character array. * * @param startIndex the start index, inclusive, must be valid. * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string. * @return a new array that holds part of the contents of the builder. * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than size is valid). */ public char[] toCharArray(final int startIndex, int endIndex) { endIndex = validateRange(startIndex, endIndex); final int len = endIndex - startIndex; if (len == 0) { return ArrayUtils.EMPTY_CHAR_ARRAY; } final char[] chars = new char[len]; System.arraycopy(buffer, startIndex, chars, 0, len); return chars; } /** * Gets a String version of the string builder, creating a new instance each time the method is called. *

* Note that unlike StringBuffer, the string version returned is independent of the string builder. *

* * @return The builder as a String. */ @Override public String toString() { return new String(buffer, 0, size); } /** * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called. * * @return The builder as a StringBuffer. */ public StringBuffer toStringBuffer() { return new StringBuffer(size).append(buffer, 0, size); } /** * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called. * * @return The builder as a StringBuilder. */ public StringBuilder toStringBuilder() { return new StringBuilder(size).append(buffer, 0, size); } /** * Trims the builder by removing characters less than or equal to a space from the beginning and end. * * @return {@code this} instance. */ public StrBuilder trim() { if (size == 0) { return this; } int len = size; final char[] buf = buffer; int pos = 0; while (pos < len && buf[pos] <= ' ') { pos++; } while (pos < len && buf[len - 1] <= ' ') { len--; } if (len < size) { delete(len, size); } if (pos > 0) { delete(0, pos); } return this; } /** * Validates parameters defining a single index in the builder. * * @param index the index, must be valid. * @throws IndexOutOfBoundsException if the index is invalid. */ protected void validateIndex(final int index) { if (index < 0 || index > size) { throw new StringIndexOutOfBoundsException(index); } } /** * Validates parameters defining a range of the builder. * * @param startIndex the start index, inclusive, must be valid. * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string. * @return The new string. * @throws IndexOutOfBoundsException if the index is invalid. */ protected int validateRange(final int startIndex, int endIndex) { if (startIndex < 0) { throw new StringIndexOutOfBoundsException(startIndex); } if (endIndex > size) { endIndex = size; } if (startIndex > endIndex) { throw new StringIndexOutOfBoundsException("end < start"); } return endIndex; } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/StrLookup.java000066400000000000000000000160711511432740600313660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.ResourceBundle; import org.apache.commons.text.lookup.StringLookup; import org.apache.commons.text.lookup.StringLookupFactory; /** * Lookup a String key to a String value. *

* This class represents the simplest form of a string to string map. It has a benefit over a map in that it can create * the result on demand based on the key. *

*

* This class comes complete with various factory methods. If these do not suffice, you can subclass and implement your * own matcher. *

*

* For example, it would be possible to implement a lookup that used the key as a primary key, and looked up the value * on demand from the database *

* * @param the type of the values supported by the lookup * @since 1.0 * @deprecated Deprecated as of 1.3, use {@link StringLookupFactory} instead. This class will be removed in 2.0. */ @Deprecated public abstract class StrLookup implements StringLookup { /** * Lookup implementation that uses a Map. * * @param the type of the values supported by the lookup */ private static final class MapStrLookup extends StrLookup { /** Map keys are variable names and value. */ private final Map map; /** * Creates a new instance backed by a Map. * * @param map the map of keys to values, may be null */ private MapStrLookup(final Map map) { this.map = map != null ? map : Collections.emptyMap(); } /** * Looks up a String key to a String value using the map. *

* If the map is null, then null is returned. The map result object is converted to a string using toString(). *

* * @param key the key to be looked up, may be null * @return The matching value, null if no match */ @Override public String lookup(final String key) { return Objects.toString(map.get(key), null); } @Override public String toString() { return super.toString() + " [map=" + map + "]"; } } /** * Lookup implementation based on a ResourceBundle. */ private static final class ResourceBundleLookup extends StrLookup { /** ResourceBundle keys are variable names and value. */ private final ResourceBundle resourceBundle; /** * Creates a new instance backed by a ResourceBundle. * * @param resourceBundle the ResourceBundle of keys to values, may be null. */ private ResourceBundleLookup(final ResourceBundle resourceBundle) { this.resourceBundle = resourceBundle; } @Override public String lookup(final String key) { if (resourceBundle == null || key == null || !resourceBundle.containsKey(key)) { return null; } return resourceBundle.getString(key); } @Override public String toString() { return super.toString() + " [resourceBundle=" + resourceBundle + "]"; } } /** * Lookup implementation based on system properties. */ private static final class SystemPropertiesStrLookup extends StrLookup { /** * Private for Spotbugs SING_SINGLETON_GETTER_NOT_SYNCHRONIZED. */ private SystemPropertiesStrLookup() { // default } /** * {@inheritDoc} This implementation directly accesses system properties. */ @Override public String lookup(final String key) { if (!key.isEmpty()) { try { return System.getProperty(key); } catch (final SecurityException ignored) { // Noop: All lookup(String) will return null. } } return null; } } /** * Lookup that always returns null. */ private static final StrLookup NONE_LOOKUP = new MapStrLookup<>(null); /** * Lookup based on system properties. */ private static final StrLookup SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup(); /** * Returns a lookup which looks up values using a map. *

* If the map is null, then null will be returned from every lookup. The map result object is converted to a string * using toString(). *

* * @param the type of the values supported by the lookup. * @param map the map of keys to values, may be null. * @return a lookup using the map, not null. */ public static StrLookup mapLookup(final Map map) { return new MapStrLookup<>(map); } /** * Returns a lookup which always returns null. * * @return a lookup that always returns null, not null. */ public static StrLookup noneLookup() { return NONE_LOOKUP; } /** * Returns a lookup which looks up values using a ResourceBundle. *

* If the ResourceBundle is null, then null will be returned from every lookup. The map result object is converted * to a string using toString(). *

* * @param resourceBundle the map of keys to values, may be null. * @return a lookup using the map, not null. * @see StringLookupFactory#resourceBundleStringLookup(String) */ public static StrLookup resourceBundleLookup(final ResourceBundle resourceBundle) { return new ResourceBundleLookup(resourceBundle); } /** * Returns a new lookup which uses a copy of the current {@link System#getProperties() System properties}. *

* If a security manager blocked access to system properties, then null will be returned from every lookup. *

*

* If a null key is used, this lookup will throw a NullPointerException. *

* * @return a lookup using system properties, not null. */ public static StrLookup systemPropertiesLookup() { return SYSTEM_PROPERTIES_LOOKUP; } /** * Constructs a new instance for subclasses. */ protected StrLookup() { } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/StrMatcher.java000066400000000000000000000351271511432740600315030ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.Arrays; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.text.matcher.StringMatcherFactory; /** * A matcher class that can be queried to determine if a character array * portion matches. *

* This class comes complete with various factory methods. * If these do not suffice, you can subclass and implement your own matcher. *

* * @since 1.0 * @deprecated Deprecated as of 1.3, use {@link StringMatcherFactory} instead. This class will be removed in 2.0. */ @Deprecated public abstract class StrMatcher { /** * Class used to define a character for matching purposes. */ private static final class CharMatcher extends StrMatcher { /** The character to match. */ private final char ch; /** * Constructor that creates a matcher that matches a single character. * * @param ch the character to match. */ private CharMatcher(final char ch) { this.ch = ch; } /** * Returns {@code 1} if there is a match, or {@code 0} if there is no match. * * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @param bufferStart the first active index in the buffer, valid for buffer. * @param bufferEnd the end index of the active buffer, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ @Override public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { return ch == buffer[pos] ? 1 : 0; } } /** * Class used to define a set of characters for matching purposes. */ private static final class CharSetMatcher extends StrMatcher { /** The set of characters to match. */ private final char[] chars; /** * Constructor that creates a matcher from a character array. * * @param chars the characters to match, must not be null */ private CharSetMatcher(final char[] chars) { this.chars = chars.clone(); Arrays.sort(this.chars); } /** * Returns {@code 1} if there is a match, or {@code 0} if there is no match. * * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @param bufferStart the first active index in the buffer, valid for buffer. * @param bufferEnd the end index of the active buffer, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ @Override public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0; } } /** * Class used to match no characters. */ private static final class NoMatcher extends StrMatcher { /** * Constructs a new instance of {@code NoMatcher}. */ private NoMatcher() { } /** * Always returns {@code 0}. * * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @param bufferStart the first active index in the buffer, valid for buffer. * @param bufferEnd the end index of the active buffer, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ @Override public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { return 0; } } /** * Class used to define a set of characters for matching purposes. */ private static final class StringMatcher extends StrMatcher { /** The string to match, as a character array. */ private final char[] chars; /** * Constructor that creates a matcher from a String. * * @param str the string to match, must not be null */ private StringMatcher(final String str) { chars = str.toCharArray(); } /** * Returns the number of matching characters, or zero if there is no match. * * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @param bufferStart the first active index in the buffer, valid for buffer. * @param bufferEnd the end index of the active buffer, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ @Override public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) { final int len = chars.length; if (pos + len > bufferEnd) { return 0; } for (int i = 0; i < chars.length; i++, pos++) { if (chars[i] != buffer[pos]) { return 0; } } return len; } @Override public String toString() { return super.toString() + ' ' + Arrays.toString(chars); } } /** * Class used to match whitespace as per trim(). */ private static final class TrimMatcher extends StrMatcher { /** * Constructs a new instance of {@code TrimMatcher}. */ private TrimMatcher() { } /** * Returns whether or not the given character matches. * * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @param bufferStart the first active index in the buffer, valid for buffer. * @param bufferEnd the end index of the active buffer, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ @Override public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { return buffer[pos] <= 32 ? 1 : 0; } } /** * Matches the comma character. */ private static final StrMatcher COMMA_MATCHER = new CharMatcher(','); /** * Matches the tab character. */ private static final StrMatcher TAB_MATCHER = new CharMatcher('\t'); /** * Matches the space character. */ private static final StrMatcher SPACE_MATCHER = new CharMatcher(' '); /** * Matches the same characters as StringTokenizer, * namely space, tab, newline, form feed. */ private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray()); /** * Matches the String trim() whitespace characters. */ private static final StrMatcher TRIM_MATCHER = new TrimMatcher(); /** * Matches the double quote character. */ private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\''); /** * Matches the double quote character. */ private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"'); /** * Matches the single or double quote character. */ private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray()); /** * Matches no characters. */ private static final StrMatcher NONE_MATCHER = new NoMatcher(); /** * Creates a matcher from a character. * * @param ch the character to match, must not be null. * @return a new Matcher for the given char. */ public static StrMatcher charMatcher(final char ch) { return new CharMatcher(ch); } /** * Creates a matcher from a set of characters. * * @param chars the characters to match, null or empty matches nothing. * @return a new matcher for the given char[]. */ public static StrMatcher charSetMatcher(final char... chars) { if (ArrayUtils.isEmpty(chars)) { return NONE_MATCHER; } if (chars.length == 1) { return new CharMatcher(chars[0]); } return new CharSetMatcher(chars); } /** * Creates a matcher from a string representing a set of characters. * * @param chars the characters to match, null or empty matches nothing. * @return a new Matcher for the given characters. */ public static StrMatcher charSetMatcher(final String chars) { if (chars == null || chars.isEmpty()) { return NONE_MATCHER; } if (chars.length() == 1) { return new CharMatcher(chars.charAt(0)); } return new CharSetMatcher(chars.toCharArray()); } /** * Returns a matcher which matches the comma character. * * @return a matcher for a comma. */ public static StrMatcher commaMatcher() { return COMMA_MATCHER; } /** * Returns a matcher which matches the double quote character. * * @return a matcher for a double quote. */ public static StrMatcher doubleQuoteMatcher() { return DOUBLE_QUOTE_MATCHER; } /** * Matches no characters. * * @return a matcher that matches nothing. */ public static StrMatcher noneMatcher() { return NONE_MATCHER; } /** * Returns a matcher which matches the single or double quote character. * * @return a matcher for a single or double quote. */ public static StrMatcher quoteMatcher() { return QUOTE_MATCHER; } /** * Returns a matcher which matches the single quote character. * * @return a matcher for a single quote. */ public static StrMatcher singleQuoteMatcher() { return SINGLE_QUOTE_MATCHER; } /** * Returns a matcher which matches the space character. * * @return a matcher for a space. */ public static StrMatcher spaceMatcher() { return SPACE_MATCHER; } /** * Matches the same characters as StringTokenizer, * namely space, tab, newline and form feed. * * @return The split matcher. */ public static StrMatcher splitMatcher() { return SPLIT_MATCHER; } /** * Creates a matcher from a string. * * @param str the string to match, null or empty matches nothing * @return a new Matcher for the given String */ public static StrMatcher stringMatcher(final String str) { if (str == null || str.isEmpty()) { return NONE_MATCHER; } return new StringMatcher(str); } /** * Returns a matcher which matches the tab character. * * @return a matcher for a tab. */ public static StrMatcher tabMatcher() { return TAB_MATCHER; } /** * Matches the String trim() whitespace characters. * * @return The trim matcher. */ public static StrMatcher trimMatcher() { return TRIM_MATCHER; } /** * Constructs a new instance. */ protected StrMatcher() { } /** * Returns the number of matching characters, or zero if there is no match. *

* This method is called to check for a match. * The parameter {@code pos} represents the current position to be * checked in the string {@code buffer} (a character array which must * not be changed). * The API guarantees that {@code pos} is a valid index for {@code buffer}. *

*

* The matching code may check one character or many. * It may check characters preceding {@code pos} as well as those after. *

*

* It must return zero for no match, or a positive number if a match was found. * The number indicates the number of characters that matched. *

* * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ public int isMatch(final char[] buffer, final int pos) { return isMatch(buffer, pos, 0, buffer.length); } /** * Returns the number of matching characters, or zero if there is no match. *

* This method is called to check for a match. * The parameter {@code pos} represents the current position to be * checked in the string {@code buffer} (a character array which must * not be changed). * The API guarantees that {@code pos} is a valid index for {@code buffer}. *

*

* The character array may be larger than the active area to be matched. * Only values in the buffer between the specified indices may be accessed. *

*

* The matching code may check one character or many. * It may check characters preceding {@code pos} as well as those * after, so long as no checks exceed the bounds specified. *

*

* It must return zero for no match, or a positive number if a match was found. * The number indicates the number of characters that matched. *

* * @param buffer the text content to match against, do not change. * @param pos the starting position for the match, valid for buffer. * @param bufferStart the first active index in the buffer, valid for buffer. * @param bufferEnd the end index (exclusive) of the active buffer, valid for buffer. * @return The number of matching characters, or zero if there is no match. */ public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd); } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/StrSubstitutor.java000066400000000000000000001445551511432740600324750ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.Validate; /** * Substitutes variables within a string by values. *

* This class takes a piece of text and substitutes all the variables within it. * The default definition of a variable is {@code ${variableName}}. * The prefix and suffix can be changed via constructors and set methods. *

* Variable values are typically resolved from a map, but could also be resolved * from system properties, or by supplying a custom variable resolver. *

* The simplest example is to use this class to replace Java System properties. For example: *

 * StrSubstitutor.replaceSystemProperties(
 *      "You are running with java.version = ${java.version} and os.name = ${os.name}.");
 * 
*

* Typical usage of this class follows the following pattern: First an instance is created * and initialized with the map that contains the values for the available variables. * If a prefix and/or suffix for variables should be used other than the default ones, * the appropriate settings can be performed. After that the {@code replace()} * method can be called passing in the source text for interpolation. In the returned * text all variable references (as long as their values are known) will be resolved. * The following example demonstrates this: *

 * Map<String, String> valuesMap = new HashMap<>();
 * valuesMap.put("animal", "quick brown fox");
 * valuesMap.put("target", "lazy dog");
 * String templateString = "The ${animal} jumped over the ${target}.";
 * StrSubstitutor sub = new StrSubstitutor(valuesMap);
 * String resolvedString = sub.replace(templateString);
 * 
* yielding: *
 *      The quick brown fox jumped over the lazy dog.
 * 
*

* Also, this class allows to set a default value for unresolved variables. * The default value for a variable can be appended to the variable name after the variable * default value delimiter. The default value of the variable default value delimiter is ':-', * as in bash and other *nix shells, as those are arguably where the default ${} delimiter set originated. * The variable default value delimiter can be manually set by calling {@link #setValueDelimiterMatcher(StrMatcher)}, * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}. * The following shows an example with variable default value settings: *

 * Map<String, String> valuesMap = new HashMap<>();
 * valuesMap.put("animal", "quick brown fox");
 * valuesMap.put("target", "lazy dog");
 * String templateString = "The ${animal} jumped over the ${target}. ${undefined.number:-1234567890}.";
 * StrSubstitutor sub = new StrSubstitutor(valuesMap);
 * String resolvedString = sub.replace(templateString);
 * 
* yielding: *
 *      The quick brown fox jumped over the lazy dog. 1234567890.
 * 
*

* In addition to this usage pattern there are some static convenience methods that * cover the most common use cases. These methods can be used without the need of * manually creating an instance. However if multiple replace operations are to be * performed, creating and reusing an instance of this class will be more efficient. *

* Variable replacement works in a recursive way. Thus, if a variable value contains * a variable then that variable will also be replaced. Cyclic replacements are * detected and will cause an exception to be thrown. *

* Sometimes the interpolation's result must contain a variable prefix. As an example * take the following source text: *

 *   The variable ${${name}} must be used.
 * 
* Here only the variable's name referred to in the text should be replaced resulting * in the text (assuming that the value of the {@code name} variable is {@code x}): *
 *   The variable ${x} must be used.
 * 
* To achieve this effect there are two possibilities: Either set a different prefix * and suffix for variables which do not conflict with the result text you want to * produce. The other possibility is to use the escape character, by default '$'. * If this character is placed before a variable reference, this reference is ignored * and won't be replaced. For example: *
 *   The variable $${${name}} must be used.
 * 
*

* In some complex scenarios you might even want to perform substitution in the * names of variables, for instance *

 * ${jre-${java.specification.version}}
 * 
* {@code StrSubstitutor} supports this recursive substitution in variable * names, but it has to be enabled explicitly by setting the * {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables} * property to true. *

This class is not thread safe.

* * @since 1.0 * @deprecated Deprecated as of 1.3, use {@link StringSubstitutor} instead. This class will be removed in 2.0. */ @Deprecated public class StrSubstitutor { /** * Constant for the default escape character. */ public static final char DEFAULT_ESCAPE = '$'; /** * Constant for the default variable prefix. */ public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${"); /** * Constant for the default variable suffix. */ public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}"); /** * Constant for the default value delimiter of a variable. */ public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(":-"); /** * Replaces all the occurrences of variables in the given source object with * their matching values from the map. * * @param the type of the values in the map. * @param source the source text containing the variables to substitute, null returns null. * @param valueMap the map with the values, may be null. * @return The result of the replace operation. */ public static String replace(final Object source, final Map valueMap) { return new StrSubstitutor(valueMap).replace(source); } /** * Replaces all the occurrences of variables in the given source object with * their matching values from the map. This method allows to specify a * custom variable prefix and suffix * * @param the type of the values in the map. * @param source the source text containing the variables to substitute, null returns null. * @param valueMap the map with the values, may be null. * @param prefix the prefix of variables, not null. * @param suffix the suffix of variables, not null. * @return The result of the replace operation. * @throws IllegalArgumentException if the prefix or suffix is null. */ public static String replace(final Object source, final Map valueMap, final String prefix, final String suffix) { return new StrSubstitutor(valueMap, prefix, suffix).replace(source); } /** * Replaces all the occurrences of variables in the given source object with their matching * values from the properties. * * @param source the source text containing the variables to substitute, null returns null. * @param valueProperties the properties with values, may be null. * @return The result of the replace operation. */ public static String replace(final Object source, final Properties valueProperties) { if (valueProperties == null) { return source.toString(); } return replace(source, valueProperties.stringPropertyNames().stream().collect(Collectors.toMap(Function.identity(), valueProperties::getProperty))); } /** * Replaces all the occurrences of variables in the given source object with * their matching values from the system properties. * * @param source the source text containing the variables to substitute, null returns null. * @return The result of the replace operation. */ public static String replaceSystemProperties(final Object source) { return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source); } /** * Stores the escape character. */ private char escapeChar; /** * Stores the variable prefix. */ private StrMatcher prefixMatcher; /** * Stores the variable suffix. */ private StrMatcher suffixMatcher; /** * Stores the default variable value delimiter. */ private StrMatcher valueDelimiterMatcher; /** * Variable resolution is delegated to an implementor of VariableResolver. */ private StrLookup variableResolver; /** * The flag whether substitution in variable names is enabled. */ private boolean enableSubstitutionInVariables; /** * Whether escapes should be preserved. Default is false; */ private boolean preserveEscapes; /** * The flag whether substitution in variable values is disabled. */ private boolean disableSubstitutionInValues; /** * Constructs a new instance with defaults for variable prefix and suffix * and the escaping character. */ public StrSubstitutor() { this(null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); } /** * Constructs a new instance and initializes it. Uses defaults for variable * prefix and suffix and the escaping character. * * @param the type of the values in the map. * @param valueMap the map with the variables' values, may be null. */ public StrSubstitutor(final Map valueMap) { this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); } /** * Constructs a new instance and initializes it. Uses a default escaping character. * * @param the type of the values in the map. * @param valueMap the map with the variables' values, may be null. * @param prefix the prefix for variables, not null. * @param suffix the suffix for variables, not null. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor(final Map valueMap, final String prefix, final String suffix) { this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE); } /** * Constructs a new instance and initializes it. * * @param the type of the values in the map. * @param valueMap the map with the variables' values, may be null. * @param prefix the prefix for variables, not null. * @param suffix the suffix for variables, not null. * @param escape the escape character. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor(final Map valueMap, final String prefix, final String suffix, final char escape) { this(StrLookup.mapLookup(valueMap), prefix, suffix, escape); } /** * Constructs a new instance and initializes it. * * @param the type of the values in the map. * @param valueMap the map with the variables' values, may be null. * @param prefix the prefix for variables, not null. * @param suffix the suffix for variables, not null. * @param escape the escape character. * @param valueDelimiter the variable default value delimiter, may be null. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor(final Map valueMap, final String prefix, final String suffix, final char escape, final String valueDelimiter) { this(StrLookup.mapLookup(valueMap), prefix, suffix, escape, valueDelimiter); } /** * Constructs a new instance and initializes it. * * @param variableResolver the variable resolver, may be null. */ public StrSubstitutor(final StrLookup variableResolver) { this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); } /** * Constructs a new instance and initializes it. * * @param variableResolver the variable resolver, may be null. * @param prefix the prefix for variables, not null. * @param suffix the suffix for variables, not null. * @param escape the escape character. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor(final StrLookup variableResolver, final String prefix, final String suffix, final char escape) { setVariableResolver(variableResolver); setVariablePrefix(prefix); setVariableSuffix(suffix); setEscapeChar(escape); setValueDelimiterMatcher(DEFAULT_VALUE_DELIMITER); } /** * Constructs a new instance and initializes it. * * @param variableResolver the variable resolver, may be null. * @param prefix the prefix for variables, not null. * @param suffix the suffix for variables, not null. * @param escape the escape character. * @param valueDelimiter the variable default value delimiter string, may be null. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor(final StrLookup variableResolver, final String prefix, final String suffix, final char escape, final String valueDelimiter) { setVariableResolver(variableResolver); setVariablePrefix(prefix); setVariableSuffix(suffix); setEscapeChar(escape); setValueDelimiter(valueDelimiter); } /** * Constructs a new instance and initializes it. * * @param variableResolver the variable resolver, may be null. * @param prefixMatcher the prefix for variables, not null. * @param suffixMatcher the suffix for variables, not null. * @param escape the escape character. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor( final StrLookup variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher, final char escape) { this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER); } /** * Constructs a new instance and initializes it. * * @param variableResolver the variable resolver, may be null. * @param prefixMatcher the prefix for variables, not null. * @param suffixMatcher the suffix for variables, not null. * @param escape the escape character. * @param valueDelimiterMatcher the variable default value delimiter matcher, may be null. * @throws IllegalArgumentException if the prefix or suffix is null. */ public StrSubstitutor( final StrLookup variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher, final char escape, final StrMatcher valueDelimiterMatcher) { setVariableResolver(variableResolver); setVariablePrefixMatcher(prefixMatcher); setVariableSuffixMatcher(suffixMatcher); setEscapeChar(escape); setValueDelimiterMatcher(valueDelimiterMatcher); } /** * Checks if the specified variable is already in the stack (list) of variables. * * @param varName the variable name to check. * @param priorVariables the list of prior variables. */ private void checkCyclicSubstitution(final String varName, final List priorVariables) { if (!priorVariables.contains(varName)) { return; } final StrBuilder buf = new StrBuilder(256); buf.append("Infinite loop in property interpolation of "); buf.append(priorVariables.remove(0)); buf.append(": "); buf.appendWithSeparators(priorVariables, "->"); throw new IllegalStateException(buf.toString()); } /** * Returns the escape character. * * @return The character used for escaping variable references. */ public char getEscapeChar() { return this.escapeChar; } /** * Gets the variable default value delimiter matcher currently in use. *

* The variable default value delimiter is the character or characters that delimit the variable name and the variable default value. This delimiter is * expressed in terms of a matcher allowing advanced variable default value delimiter matches. *

*

* If it returns null, then the variable default value resolution is disabled. *

* * @return The variable default value delimiter matcher in use, may be null. */ public StrMatcher getValueDelimiterMatcher() { return valueDelimiterMatcher; } /** * Gets the variable prefix matcher currently in use. *

* The variable prefix is the character or characters that identify the start of a variable. This prefix is expressed in terms of a matcher allowing * advanced prefix matches. *

* * @return The prefix matcher in use. */ public StrMatcher getVariablePrefixMatcher() { return prefixMatcher; } /** * Gets the VariableResolver that is used to lookup variables. * * @return The VariableResolver. */ public StrLookup getVariableResolver() { return this.variableResolver; } /** * Gets the variable suffix matcher currently in use. *

* The variable suffix is the character or characters that identify the end of a variable. This suffix is expressed in terms of a matcher allowing advanced * suffix matches. *

* * @return The suffix matcher in use. */ public StrMatcher getVariableSuffixMatcher() { return suffixMatcher; } /** * Returns a flag whether substitution is disabled in variable values.If set to * true, the values of variables can contain other variables will not be * processed and substituted original variable is evaluated, e.g. *
     * Map<String, String> valuesMap = new HashMap<>();
     * valuesMap.put("name", "Douglas ${surname}");
     * valuesMap.put("surname", "Crockford");
     * String templateString = "Hi ${name}";
     * StrSubstitutor sub = new StrSubstitutor(valuesMap);
     * String resolvedString = sub.replace(templateString);
     * 
*

* yielding: *

*
     *      Hi Douglas ${surname}
     * 
* * @return The substitution in variable values flag. * @since 1.2 */ public boolean isDisableSubstitutionInValues() { return disableSubstitutionInValues; } /** * Returns a flag whether substitution is done in variable names. * * @return The substitution in variable names flag. */ public boolean isEnableSubstitutionInVariables() { return enableSubstitutionInVariables; } /** * Returns the flag controlling whether escapes are preserved during substitution. * * @return The preserve escape flag. */ public boolean isPreserveEscapes() { return preserveEscapes; } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source array as a template. The array is not * altered by this method. * * @param source the character array to replace in, not altered, null returns null. * @return The result of the replace operation. */ public String replace(final char[] source) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(source.length).append(source); substitute(buf, 0, source.length); return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source array as a template. The array is not * altered by this method. *

* Only the specified portion of the array will be processed. The rest of the array is not processed, and is not returned. *

* * @param source the character array to replace in, not altered, null returns null. * @param offset the start offset within the array, must be valid. * @param length the length within the array to be processed, must be valid. * @return The result of the replace operation. */ public String replace(final char[] source, final int offset, final int length) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); substitute(buf, 0, length); return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source as a template. The source is not altered by * this method. * * @param source the buffer to use as a template, not changed, null returns null. * @return The result of the replace operation. */ public String replace(final CharSequence source) { if (source == null) { return null; } return replace(source, 0, source.length()); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source as a template. The source is not altered by * this method. *

* Only the specified portion of the buffer will be processed. The rest of the buffer is not processed, and is not returned. *

* * @param source the buffer to use as a template, not changed, null returns null. * @param offset the start offset within the array, must be valid. * @param length the length within the array to be processed, must be valid. * @return The result of the replace operation. */ public String replace(final CharSequence source, final int offset, final int length) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); substitute(buf, 0, length); return buf.toString(); } /** * Replaces all the occurrences of variables in the given source object with their matching values from the resolver. The input source object is converted * to a string using {@code toString} and is not altered. * * @param source the source to replace in, null returns null. * @return The result of the replace operation. */ public String replace(final Object source) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder().append(source); substitute(buf, 0, buf.length()); return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source builder as a template. The builder is not * altered by this method. * * @param source the builder to use as a template, not changed, null returns null. * @return The result of the replace operation. */ public String replace(final StrBuilder source) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(source.length()).append(source); substitute(buf, 0, buf.length()); return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source builder as a template. The builder is not * altered by this method. *

* Only the specified portion of the builder will be processed. The rest of the builder is not processed, and is not returned. *

* * @param source the builder to use as a template, not changed, null returns null. * @param offset the start offset within the array, must be valid. * @param length the length within the array to be processed, must be valid. * @return The result of the replace operation. */ public String replace(final StrBuilder source, final int offset, final int length) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); substitute(buf, 0, length); return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source string as a template. * * @param source the string to replace in, null returns null. * @return The result of the replace operation. */ public String replace(final String source) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(source); if (!substitute(buf, 0, source.length())) { return source; } return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source string as a template. *

* Only the specified portion of the string will be processed. The rest of the string is not processed, and is not returned. *

* * @param source the string to replace in, null returns null. * @param offset the start offset within the array, must be valid. * @param length the length within the array to be processed, must be valid. * @return The result of the replace operation. */ public String replace(final String source, final int offset, final int length) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); if (!substitute(buf, 0, length)) { return source.substring(offset, offset + length); } return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source buffer as a template. The buffer is not * altered by this method. * * @param source the buffer to use as a template, not changed, null returns null. * @return The result of the replace operation. */ public String replace(final StringBuffer source) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(source.length()).append(source); substitute(buf, 0, buf.length()); return buf.toString(); } /** * Replaces all the occurrences of variables with their matching values from the resolver using the given source buffer as a template. The buffer is not * altered by this method. *

* Only the specified portion of the buffer will be processed. The rest of the buffer is not processed, and is not returned. *

* * @param source the buffer to use as a template, not changed, null returns null. * @param offset the start offset within the array, must be valid. * @param length the length within the array to be processed, must be valid. * @return The result of the replace operation. */ public String replace(final StringBuffer source, final int offset, final int length) { if (source == null) { return null; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); substitute(buf, 0, length); return buf.toString(); } /** * Replaces all the occurrences of variables within the given source builder with their matching values from the resolver. * * @param source the builder to replace in, updated, null returns zero. * @return true if altered. */ public boolean replaceIn(final StrBuilder source) { if (source == null) { return false; } return substitute(source, 0, source.length()); } /** * Replaces all the occurrences of variables within the given source builder with their matching values from the resolver. *

* Only the specified portion of the builder will be processed. The rest of the builder is not processed, but it is not deleted. *

* * @param source the builder to replace in, null returns zero. * @param offset the start offset within the array, must be valid. * @param length the length within the builder to be processed, must be valid. * @return true if altered. */ public boolean replaceIn(final StrBuilder source, final int offset, final int length) { if (source == null) { return false; } return substitute(source, offset, length); } /** * Replaces all the occurrences of variables within the given source buffer with their matching values from the resolver. The buffer is updated with the * result. * * @param source the buffer to replace in, updated, null returns zero. * @return true if altered. */ public boolean replaceIn(final StringBuffer source) { if (source == null) { return false; } return replaceIn(source, 0, source.length()); } /** * Replaces all the occurrences of variables within the given source buffer with their matching values from the resolver. The buffer is updated with the * result. *

* Only the specified portion of the buffer will be processed. The rest of the buffer is not processed, but it is not deleted. *

* * @param source the buffer to replace in, updated, null returns zero. * @param offset the start offset within the array, must be valid. * @param length the length within the buffer to be processed, must be valid. * @return true if altered. */ public boolean replaceIn(final StringBuffer source, final int offset, final int length) { if (source == null) { return false; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); if (!substitute(buf, 0, length)) { return false; } source.replace(offset, offset + length, buf.toString()); return true; } /** * Replaces all the occurrences of variables within the given source buffer with their matching values from the resolver. The buffer is updated with the * result. * * @param source the buffer to replace in, updated, null returns zero. * @return true if altered. */ public boolean replaceIn(final StringBuilder source) { if (source == null) { return false; } return replaceIn(source, 0, source.length()); } /** * Replaces all the occurrences of variables within the given source builder with their matching values from the resolver. The builder is updated with the * result. *

* Only the specified portion of the buffer will be processed. The rest of the buffer is not processed, but it is not deleted. *

* * @param source the buffer to replace in, updated, null returns zero. * @param offset the start offset within the array, must be valid. * @param length the length within the buffer to be processed, must be valid. * @return true if altered. */ public boolean replaceIn(final StringBuilder source, final int offset, final int length) { if (source == null) { return false; } final StrBuilder buf = new StrBuilder(length).append(source, offset, length); if (!substitute(buf, 0, length)) { return false; } source.replace(offset, offset + length, buf.toString()); return true; } /** * Internal method that resolves the value of a variable. *

* Most users of this class do not need to call this method. This method is called automatically by the substitution process. *

*

* Writers of subclasses can override this method if they need to alter how each substitution occurs. The method is passed the variable's name and must * return the corresponding value. This implementation uses the {@link #getVariableResolver()} with the variable's name as the key. *

* * @param variableName the name of the variable, not null. * @param buf the buffer where the substitution is occurring, not null. * @param startPos the start position of the variable including the prefix, valid. * @param endPos the end position of the variable including the suffix, valid. * @return The variable's value or null if the variable is unknown. */ protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) { final StrLookup resolver = getVariableResolver(); if (resolver == null) { return null; } return resolver.apply(variableName); } /** * Sets a flag whether substitution is done in variable values (recursive). * * @param disableSubstitutionInValues true if substitution in variable value are disabled. * @since 1.2 */ public void setDisableSubstitutionInValues(final boolean disableSubstitutionInValues) { this.disableSubstitutionInValues = disableSubstitutionInValues; } /** * Sets a flag whether substitution is done in variable names. If set to true, the names of variables can contain other variables which are * processed first before the original variable is evaluated, e.g. {@code ${jre-${java.version}}}. The default value is false. * * @param enableSubstitutionInVariables the new value of the flag. */ public void setEnableSubstitutionInVariables(final boolean enableSubstitutionInVariables) { this.enableSubstitutionInVariables = enableSubstitutionInVariables; } /** * Sets the escape character. If this character is placed before a variable reference in the source text, this variable will be ignored. * * @param escapeCharacter the escape character (0 for disabling escaping) */ public void setEscapeChar(final char escapeCharacter) { this.escapeChar = escapeCharacter; } /** * Sets a flag controlling whether escapes are preserved during substitution. If set to true, the escape character is retained during * substitution (e.g. {@code $${this-is-escaped}} remains {@code $${this-is-escaped}}). If set to false, the escape character is removed * during substitution (e.g. {@code $${this-is-escaped}} becomes {@code ${this-is-escaped}}). The default value is false * * @param preserveEscapes true if escapes are to be preserved */ public void setPreserveEscapes(final boolean preserveEscapes) { this.preserveEscapes = preserveEscapes; } /** * Sets the variable default value delimiter to use. *

* The variable default value delimiter is the character or characters that delimit the variable name and the variable default value. This method allows a * single character variable default value delimiter to be easily set. *

* * @param valueDelimiter the variable default value delimiter character to use. * @return {@code this} instance. */ public StrSubstitutor setValueDelimiter(final char valueDelimiter) { return setValueDelimiterMatcher(StrMatcher.charMatcher(valueDelimiter)); } /** * Sets the variable default value delimiter to use. *

* The variable default value delimiter is the character or characters that delimit the variable name and the variable default value. This method allows a * string variable default value delimiter to be easily set. *

*

* If the {@code valueDelimiter} is null or empty string, then the variable default value resolution becomes disabled. *

* * @param valueDelimiter the variable default value delimiter string to use, may be null or empty * @return {@code this} instance. */ public StrSubstitutor setValueDelimiter(final String valueDelimiter) { if (valueDelimiter == null || valueDelimiter.isEmpty()) { setValueDelimiterMatcher(null); return this; } return setValueDelimiterMatcher(StrMatcher.stringMatcher(valueDelimiter)); } /** * Sets the variable default value delimiter matcher to use. *

* The variable default value delimiter is the character or characters that delimit the variable name and the variable default value. This delimiter is * expressed in terms of a matcher allowing advanced variable default value delimiter matches. *

*

* If the {@code valueDelimiterMatcher} is null, then the variable default value resolution becomes disabled. *

* * @param valueDelimiterMatcher variable default value delimiter matcher to use, may be null * @return {@code this} instance. */ public StrSubstitutor setValueDelimiterMatcher(final StrMatcher valueDelimiterMatcher) { this.valueDelimiterMatcher = valueDelimiterMatcher; return this; } /** * Sets the variable prefix to use. *

* The variable prefix is the character or characters that identify the start of a variable. This method allows a single character prefix to be easily set. *

* * @param prefix the prefix character to use. * @return {@code this} instance. */ public StrSubstitutor setVariablePrefix(final char prefix) { return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix)); } /** * Sets the variable prefix to use. *

* The variable prefix is the character or characters that identify the start of a variable. This method allows a string prefix to be easily set. *

* * @param prefix the prefix for variables, not null. * @return {@code this} instance. * @throws IllegalArgumentException if the prefix is null. */ public StrSubstitutor setVariablePrefix(final String prefix) { Validate.isTrue(prefix != null, "Variable prefix must not be null!"); return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix)); } /** * Sets the variable prefix matcher currently in use. *

* The variable prefix is the character or characters that identify the start of a variable. This prefix is expressed in terms of a matcher allowing * advanced prefix matches. *

* * @param prefixMatcher the prefix matcher to use, null ignored. * @return {@code this} instance. * @throws IllegalArgumentException if the prefix matcher is null. */ public StrSubstitutor setVariablePrefixMatcher(final StrMatcher prefixMatcher) { Validate.isTrue(prefixMatcher != null, "Variable prefix matcher must not be null!"); this.prefixMatcher = prefixMatcher; return this; } /** * Sets the VariableResolver that is used to lookup variables. * * @param variableResolver the VariableResolver. */ public void setVariableResolver(final StrLookup variableResolver) { this.variableResolver = variableResolver; } /** * Sets the variable suffix to use. *

* The variable suffix is the character or characters that identify the end of a variable. This method allows a single character suffix to be easily set. *

* * @param suffix the suffix character to use. * @return {@code this} instance. */ public StrSubstitutor setVariableSuffix(final char suffix) { return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix)); } /** * Sets the variable suffix to use. *

* The variable suffix is the character or characters that identify the end of a variable. This method allows a string suffix to be easily set. *

* * @param suffix the suffix for variables, not null. * @return {@code this} instance. * @throws IllegalArgumentException if the suffix is null. */ public StrSubstitutor setVariableSuffix(final String suffix) { Validate.isTrue(suffix != null, "Variable suffix must not be null!"); return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix)); } /** * Sets the variable suffix matcher currently in use. *

* The variable suffix is the character or characters that identify the end of a variable. This suffix is expressed in terms of a matcher allowing advanced * suffix matches. *

* * @param suffixMatcher the suffix matcher to use, null ignored. * @return {@code this} instance. * @throws IllegalArgumentException if the suffix matcher is null. */ public StrSubstitutor setVariableSuffixMatcher(final StrMatcher suffixMatcher) { Validate.isTrue(suffixMatcher != null, "Variable suffix matcher must not be null!"); this.suffixMatcher = suffixMatcher; return this; } /** * Internal method that substitutes the variables. *

* Most users of this class do not need to call this method. This method will be called automatically by another (public) method. *

*

* Writers of subclasses can override this method if they need access to the substitution process at the start or end. *

* * @param buf the string builder to substitute into, not null. * @param offset the start offset within the builder, must be valid. * @param length the length within the builder to be processed, must be valid. * @return true if altered. */ protected boolean substitute(final StrBuilder buf, final int offset, final int length) { return substitute(buf, offset, length, null) > 0; } /** * Recursive handler for multiple levels of interpolation. This is the main interpolation method, which resolves the values of all variable references * contained in the passed in text. * * @param buf the string builder to substitute into, not null. * @param offset the start offset within the builder, must be valid. * @param length the length within the builder to be processed, must be valid. * @param priorVariables the stack keeping track of the replaced variables, may be null. * @return The length change that occurs, unless priorVariables is null when the int represents a boolean flag as to whether any change occurred. */ private int substitute(final StrBuilder buf, final int offset, final int length, List priorVariables) { final StrMatcher pfxMatcher = getVariablePrefixMatcher(); final StrMatcher suffMatcher = getVariableSuffixMatcher(); final char escape = getEscapeChar(); final StrMatcher valueDelimMatcher = getValueDelimiterMatcher(); final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables(); final boolean substitutionInValuesDisabled = isDisableSubstitutionInValues(); final boolean top = priorVariables == null; boolean altered = false; int lengthChange = 0; char[] chars = buf.buffer; int bufEnd = offset + length; int pos = offset; while (pos < bufEnd) { final int startMatchLen = pfxMatcher.isMatch(chars, pos, offset, bufEnd); if (startMatchLen == 0) { pos++; } else // found variable start marker if (pos > offset && chars[pos - 1] == escape) { // escaped if (preserveEscapes) { pos++; continue; } buf.deleteCharAt(pos - 1); chars = buf.buffer; // in case buffer was altered lengthChange--; altered = true; bufEnd--; } else { // find suffix final int startPos = pos; pos += startMatchLen; int endMatchLen = 0; int nestedVarCount = 0; while (pos < bufEnd) { if (substitutionInVariablesEnabled && pfxMatcher.isMatch(chars, pos, offset, bufEnd) != 0) { // found a nested variable start endMatchLen = pfxMatcher.isMatch(chars, pos, offset, bufEnd); nestedVarCount++; pos += endMatchLen; continue; } endMatchLen = suffMatcher.isMatch(chars, pos, offset, bufEnd); if (endMatchLen == 0) { pos++; } else { // found variable end marker if (nestedVarCount == 0) { String varNameExpr = new String(chars, startPos + startMatchLen, pos - startPos - startMatchLen); if (substitutionInVariablesEnabled) { final StrBuilder bufName = new StrBuilder(varNameExpr); substitute(bufName, 0, bufName.length()); varNameExpr = bufName.toString(); } pos += endMatchLen; final int endPos = pos; String varName = varNameExpr; String varDefaultValue = null; if (valueDelimMatcher != null) { final char[] varNameExprChars = varNameExpr.toCharArray(); int valueDelimiterMatchLen = 0; for (int i = 0; i < varNameExprChars.length; i++) { // if there's any nested variable when nested variable substitution disabled, // then stop resolving name and default value. if (!substitutionInVariablesEnabled && pfxMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) { break; } if (valueDelimMatcher.isMatch(varNameExprChars, i) != 0) { valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, i); varName = varNameExpr.substring(0, i); varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen); break; } } } // on the first call initialize priorVariables if (priorVariables == null) { priorVariables = new ArrayList<>(); priorVariables.add(new String(chars, offset, length)); } // handle cyclic substitution checkCyclicSubstitution(varName, priorVariables); priorVariables.add(varName); // resolve the variable String varValue = resolveVariable(varName, buf, startPos, endPos); if (varValue == null) { varValue = varDefaultValue; } if (varValue != null) { final int varLen = varValue.length(); buf.replace(startPos, endPos, varValue); altered = true; int change = 0; if (!substitutionInValuesDisabled) { // recursive replace change = substitute(buf, startPos, varLen, priorVariables); } change = change + varLen - (endPos - startPos); pos += change; bufEnd += change; lengthChange += change; chars = buf.buffer; // in case buffer was // altered } // remove variable from the cyclic stack priorVariables .remove(priorVariables.size() - 1); break; } nestedVarCount--; pos += endMatchLen; } } } } if (top) { return altered ? 1 : 0; } return lengthChange; } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/StrTokenizer.java000066400000000000000000001101411511432740600320600ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; /** * Tokenizes a string based on delimiters (separators) * and supporting quoting and ignored character concepts. *

* This class can split a String into many smaller strings. It aims * to do a similar job to {@link java.util.StringTokenizer StringTokenizer}, * however it offers much more control and flexibility including implementing * the {@code ListIterator} interface. By default, it is set up * like {@code StringTokenizer}. *

* The input String is split into a number of tokens. * Each token is separated from the next String by a delimiter. * One or more delimiter characters must be specified. *

* Each token may be surrounded by quotes. * The quote matcher specifies the quote character(s). * A quote may be escaped within a quoted section by duplicating itself. *

* Between each token and the delimiter are potentially characters that need trimming. * The trimmer matcher specifies these characters. * One usage might be to trim whitespace characters. *

* At any point outside the quotes there might potentially be invalid characters. * The ignored matcher specifies these characters to be removed. * One usage might be to remove new line characters. *

* Empty tokens may be removed or returned as null. *

 * "a,b,c"         - Three tokens "a","b","c"   (comma delimiter)
 * " a, b , c "    - Three tokens "a","b","c"   (default CSV processing trims whitespace)
 * "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
 * 
* * * * * * * * * * * * * * * * * * * * * *
StrTokenizer properties and options
PropertyTypeDefault
delimCharSetMatcher{ \t\n\r\f}
quoteNoneMatcher{}
ignoreNoneMatcher{}
emptyTokenAsNullbooleanfalse
ignoreEmptyTokensbooleantrue
* * @since 1.0 * @deprecated Deprecated as of 1.3, use {@link StringTokenizer} instead. This class will be removed in 2.0. */ @Deprecated public class StrTokenizer implements ListIterator, Cloneable { /** Comma separated values tokenizer internal variable. */ // @formatter:off private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE = new StrTokenizer() .setDelimiterMatcher(StrMatcher.commaMatcher()) .setQuoteMatcher(StrMatcher.doubleQuoteMatcher()) .setIgnoredMatcher(StrMatcher.noneMatcher()) .setTrimmerMatcher(StrMatcher.trimMatcher()) .setEmptyTokenAsNull(false) .setIgnoreEmptyTokens(false); // @formatter:on /** Tab separated values tokenizer internal variable. */ // @formatter:off private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE = new StrTokenizer() .setDelimiterMatcher(StrMatcher.tabMatcher()) .setQuoteMatcher(StrMatcher.doubleQuoteMatcher()) .setIgnoredMatcher(StrMatcher.noneMatcher()) .setTrimmerMatcher(StrMatcher.trimMatcher()) .setEmptyTokenAsNull(false) .setIgnoreEmptyTokens(false); // @formatter:on /** * Returns a clone of {@code CSV_TOKENIZER_PROTOTYPE}. * * @return a clone of {@code CSV_TOKENIZER_PROTOTYPE}. */ private static StrTokenizer getCSVClone() { return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone(); } /** * Gets a new tokenizer instance which parses Comma Separated Value strings initializing it with the given input. The default for CSV processing will be * trim whitespace from both ends (which can be overridden with the setTrimmer method). *

* You must call a "reset" method to set the string which you want to parse. *

* * @return a new tokenizer instance which parses Comma Separated Value strings. */ public static StrTokenizer getCSVInstance() { return getCSVClone(); } /** * Gets a new tokenizer instance which parses Comma Separated Value strings initializing it with the given input. The default for CSV processing will be * trim whitespace from both ends (which can be overridden with the setTrimmer method). * * @param input the text to parse. * @return a new tokenizer instance which parses Comma Separated Value strings. */ public static StrTokenizer getCSVInstance(final char[] input) { final StrTokenizer tok = getCSVClone(); tok.reset(input); return tok; } /** * Gets a new tokenizer instance which parses Comma Separated Value strings initializing it with the given input. The default for CSV processing will be * trim whitespace from both ends (which can be overridden with the setTrimmer method). * * @param input the text to parse. * @return a new tokenizer instance which parses Comma Separated Value strings. */ public static StrTokenizer getCSVInstance(final String input) { final StrTokenizer tok = getCSVClone(); tok.reset(input); return tok; } /** * Returns a clone of {@code TSV_TOKENIZER_PROTOTYPE}. * * @return a clone of {@code TSV_TOKENIZER_PROTOTYPE}. */ private static StrTokenizer getTSVClone() { return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone(); } /** * Gets a new tokenizer instance which parses Tab Separated Value strings. The default for CSV processing will be trim whitespace from both ends (which can * be overridden with the setTrimmer method). *

* You must call a "reset" method to set the string which you want to parse. *

* * @return a new tokenizer instance which parses Tab Separated Value strings. */ public static StrTokenizer getTSVInstance() { return getTSVClone(); } /** * Gets a new tokenizer instance which parses Tab Separated Value strings. The default for CSV processing will be trim whitespace from both ends (which can * be overridden with the setTrimmer method). * * @param input the string to parse. * @return a new tokenizer instance which parses Tab Separated Value strings. */ public static StrTokenizer getTSVInstance(final char[] input) { final StrTokenizer tok = getTSVClone(); tok.reset(input); return tok; } /** * Gets a new tokenizer instance which parses Tab Separated Value strings. The default for CSV processing will be trim whitespace from both ends (which can * be overridden with the setTrimmer method). * * @param input the string to parse. * @return a new tokenizer instance which parses Tab Separated Value strings. */ public static StrTokenizer getTSVInstance(final String input) { final StrTokenizer tok = getTSVClone(); tok.reset(input); return tok; } /** The text to work on. */ private char[] chars; /** The parsed tokens. */ private String[] tokens; /** The current iteration position. */ private int tokenPos; /** The delimiter matcher. */ private StrMatcher delimMatcher = StrMatcher.splitMatcher(); /** The quote matcher. */ private StrMatcher quoteMatcher = StrMatcher.noneMatcher(); /** The ignored matcher. */ private StrMatcher ignoredMatcher = StrMatcher.noneMatcher(); /** The trimmer matcher. */ private StrMatcher trimmerMatcher = StrMatcher.noneMatcher(); /** Whether to return empty tokens as null. */ private boolean emptyAsNull; /** Whether to ignore empty tokens. */ private boolean ignoreEmptyTokens = true; /** * Constructs a tokenizer splitting on space, tab, newline and form feed as per StringTokenizer, but with no text to tokenize. *

* This constructor is normally used with {@link #reset(String)}. *

*/ public StrTokenizer() { this.chars = null; } /** * Constructs a tokenizer splitting on space, tab, newline and form feed * as per StringTokenizer. * * @param input the string which is to be parsed, not cloned. */ public StrTokenizer(final char[] input) { if (input == null) { this.chars = null; } else { this.chars = input.clone(); } } /** * Constructs a tokenizer splitting on the specified character. * * @param input the string which is to be parsed, not cloned. * @param delim the field delimiter character. */ public StrTokenizer(final char[] input, final char delim) { this(input); setDelimiterChar(delim); } /** * Constructs a tokenizer splitting on the specified delimiter character * and handling quotes using the specified quote character. * * @param input the string which is to be parsed, not cloned. * @param delim the field delimiter character. * @param quote the field quoted string character. */ public StrTokenizer(final char[] input, final char delim, final char quote) { this(input, delim); setQuoteChar(quote); } /** * Constructs a tokenizer splitting on the specified string. * * @param input the string which is to be parsed, not cloned. * @param delim the field delimiter string. */ public StrTokenizer(final char[] input, final String delim) { this(input); setDelimiterString(delim); } /** * Constructs a tokenizer splitting using the specified delimiter matcher. * * @param input the string which is to be parsed, not cloned. * @param delim the field delimiter matcher. */ public StrTokenizer(final char[] input, final StrMatcher delim) { this(input); setDelimiterMatcher(delim); } /** * Constructs a tokenizer splitting using the specified delimiter matcher * and handling quotes using the specified quote matcher. * * @param input the string which is to be parsed, not cloned. * @param delim the field delimiter character. * @param quote the field quoted string character. */ public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) { this(input, delim); setQuoteMatcher(quote); } /** * Constructs a tokenizer splitting on space, tab, newline and form feed * as per StringTokenizer. * * @param input the string which is to be parsed. */ public StrTokenizer(final String input) { if (input != null) { chars = input.toCharArray(); } else { chars = null; } } /** * Constructs a tokenizer splitting on the specified delimiter character. * * @param input the string which is to be parsed. * @param delim the field delimiter character. */ public StrTokenizer(final String input, final char delim) { this(input); setDelimiterChar(delim); } /** * Constructs a tokenizer splitting on the specified delimiter character * and handling quotes using the specified quote character. * * @param input the string which is to be parsed. * @param delim the field delimiter character. * @param quote the field quoted string character. */ public StrTokenizer(final String input, final char delim, final char quote) { this(input, delim); setQuoteChar(quote); } /** * Constructs a tokenizer splitting on the specified delimiter string. * * @param input the string which is to be parsed. * @param delim the field delimiter string. */ public StrTokenizer(final String input, final String delim) { this(input); setDelimiterString(delim); } /** * Constructs a tokenizer splitting using the specified delimiter matcher. * * @param input the string which is to be parsed. * @param delim the field delimiter matcher. */ public StrTokenizer(final String input, final StrMatcher delim) { this(input); setDelimiterMatcher(delim); } /** * Constructs a tokenizer splitting using the specified delimiter matcher * and handling quotes using the specified quote matcher. * * @param input the string which is to be parsed. * @param delim the field delimiter matcher. * @param quote the field quoted string matcher. */ public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) { this(input, delim); setQuoteMatcher(quote); } /** * Unsupported ListIterator operation. * @param obj this parameter ignored. * @throws UnsupportedOperationException always. */ @Override public void add(final String obj) { throw new UnsupportedOperationException("add() is unsupported"); } /** * Adds a token to a list, paying attention to the parameters we've set. * * @param list the list to add to. * @param tok the token to add. */ private void addToken(final List list, String tok) { if (tok == null || tok.isEmpty()) { if (isIgnoreEmptyTokens()) { return; } if (isEmptyTokenAsNull()) { tok = null; } } list.add(tok); } /** * Checks if tokenization has been done, and if not then do it. */ private void checkTokenized() { if (tokens == null) { if (chars == null) { // still call tokenize as subclass may do some work final List split = tokenize(null, 0, 0); tokens = split.toArray(ArrayUtils.EMPTY_STRING_ARRAY); } else { final List split = tokenize(chars, 0, chars.length); tokens = split.toArray(ArrayUtils.EMPTY_STRING_ARRAY); } } } /** * Creates a new instance of this Tokenizer. The new instance is reset so that it will be at the start of the token list. If a * {@link CloneNotSupportedException} is caught, return {@code null}. * * @return a new instance of this Tokenizer which has been reset. */ @Override public Object clone() { try { return cloneReset(); } catch (final CloneNotSupportedException ex) { return null; } } /** * Creates a new instance of this Tokenizer. The new instance is reset so that it will be at the start of the token list. * * @return a new instance of this Tokenizer which has been reset. * @throws CloneNotSupportedException if there is a problem cloning. */ Object cloneReset() throws CloneNotSupportedException { // this method exists to enable 100% test coverage final StrTokenizer cloned = (StrTokenizer) super.clone(); if (cloned.chars != null) { cloned.chars = cloned.chars.clone(); } cloned.reset(); return cloned; } /** * Gets the String content that the tokenizer is parsing. * * @return The string content being parsed. */ public String getContent() { if (chars == null) { return null; } return new String(chars); } /** * Gets the field delimiter matcher. * * @return The delimiter matcher in use. */ public StrMatcher getDelimiterMatcher() { return this.delimMatcher; } /** * Gets the ignored character matcher. *

* These characters are ignored when parsing the String, unless they are within a quoted region. The default value is not to ignore anything. *

* * @return The ignored matcher in use. */ public StrMatcher getIgnoredMatcher() { return ignoredMatcher; } /** * Gets the quote matcher currently in use. *

* The quote character is used to wrap data between the tokens. This enables delimiters to be entered as data. The default value is '"' (double quote). *

* * @return The quote matcher in use. */ public StrMatcher getQuoteMatcher() { return quoteMatcher; } /** * Gets a copy of the full token list as an independent modifiable array. * * @return The tokens as a String array. */ public String[] getTokenArray() { checkTokenized(); return tokens.clone(); } /** * Gets a copy of the full token list as an independent modifiable list. * * @return The tokens as a String array. */ public List getTokenList() { checkTokenized(); final List list = new ArrayList<>(tokens.length); Collections.addAll(list, tokens); return list; } /** * Gets the trimmer character matcher. *

* These characters are trimmed off on each side of the delimiter until the token or quote is found. The default value is not to trim anything. *

* * @return The trimmer matcher in use. */ public StrMatcher getTrimmerMatcher() { return trimmerMatcher; } /** * Checks whether there are any more tokens. * * @return true if there are more tokens. */ @Override public boolean hasNext() { checkTokenized(); return tokenPos < tokens.length; } /** * Checks whether there are any previous tokens that can be iterated to. * * @return true if there are previous tokens. */ @Override public boolean hasPrevious() { checkTokenized(); return tokenPos > 0; } /** * Gets whether the tokenizer currently returns empty tokens as null. * The default for this property is false. * * @return true if empty tokens are returned as null. */ public boolean isEmptyTokenAsNull() { return this.emptyAsNull; } /** * Gets whether the tokenizer currently ignores empty tokens. * The default for this property is true. * * @return true if empty tokens are not returned. */ public boolean isIgnoreEmptyTokens() { return ignoreEmptyTokens; } /** * Checks if the characters at the index specified match the quote * already matched in readNextToken(). * * @param srcChars the character array being tokenized. * @param pos the position to check for a quote. * @param len the length of the character array being tokenized. * @param quoteStart the start position of the matched quote, 0 if no quoting. * @param quoteLen the length of the matched quote, 0 if no quoting. * @return true if a quote is matched. */ private boolean isQuote(final char[] srcChars, final int pos, final int len, final int quoteStart, final int quoteLen) { for (int i = 0; i < quoteLen; i++) { if (pos + i >= len || srcChars[pos + i] != srcChars[quoteStart + i]) { return false; } } return true; } /** * Gets the next token. * * @return The next String token. * @throws NoSuchElementException if there are no more elements. */ @Override public String next() { if (hasNext()) { return tokens[tokenPos++]; } throw new NoSuchElementException(); } /** * Gets the index of the next token to return. * * @return The next token index. */ @Override public int nextIndex() { return tokenPos; } /** * Gets the next token from the String. Equivalent to {@link #next()} except it returns null rather than throwing {@link NoSuchElementException} when no * tokens remain. * * @return The next sequential token, or null when no more tokens are found. */ public String nextToken() { if (hasNext()) { return tokens[tokenPos++]; } return null; } /** * Gets the token previous to the last returned token. * * @return The previous token. */ @Override public String previous() { if (hasPrevious()) { return tokens[--tokenPos]; } throw new NoSuchElementException(); } /** * Gets the index of the previous token. * * @return The previous token index. */ @Override public int previousIndex() { return tokenPos - 1; } /** * Gets the previous token from the String. * * @return The previous sequential token, or null when no more tokens are found. */ public String previousToken() { if (hasPrevious()) { return tokens[--tokenPos]; } return null; } /** * Reads character by character through the String to get the next token. * * @param srcChars the character array being tokenized. * @param start the first character of field. * @param len the length of the character array being tokenized. * @param workArea a temporary work area. * @param tokenList the list of parsed tokens. * @return The starting position of the next field (the character immediately after the delimiter), or -1 if end of string found. */ private int readNextToken(final char[] srcChars, int start, final int len, final StrBuilder workArea, final List tokenList) { // skip all leading whitespace, unless it is the // field delimiter or the quote character while (start < len) { final int removeLen = Math.max( getIgnoredMatcher().isMatch(srcChars, start, start, len), getTrimmerMatcher().isMatch(srcChars, start, start, len)); if (removeLen == 0 || getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0 || getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) { break; } start += removeLen; } // handle reaching end if (start >= len) { addToken(tokenList, StringUtils.EMPTY); return -1; } // handle empty token final int delimLen = getDelimiterMatcher().isMatch(srcChars, start, start, len); if (delimLen > 0) { addToken(tokenList, StringUtils.EMPTY); return start + delimLen; } // handle found token final int quoteLen = getQuoteMatcher().isMatch(srcChars, start, start, len); if (quoteLen > 0) { return readWithQuotes(srcChars, start + quoteLen, len, workArea, tokenList, start, quoteLen); } return readWithQuotes(srcChars, start, len, workArea, tokenList, 0, 0); } /** * Reads a possibly quoted string token. * * @param srcChars the character array being tokenized. * @param start the first character of field. * @param len the length of the character array being tokenized. * @param workArea a temporary work area. * @param tokenList the list of parsed tokens. * @param quoteStart the start position of the matched quote, 0 if no quoting. * @param quoteLen the length of the matched quote, 0 if no quoting. * @return The starting position of the next field (the character immediately after the delimiter, or if end of string found, then the length of string. */ private int readWithQuotes(final char[] srcChars, final int start, final int len, final StrBuilder workArea, final List tokenList, final int quoteStart, final int quoteLen) { // Loop until we've found the end of the quoted // string or the end of the input workArea.clear(); int pos = start; boolean quoting = quoteLen > 0; int trimStart = 0; while (pos < len) { // quoting mode can occur several times throughout a string // we must switch between quoting and non-quoting until we // encounter a non-quoted delimiter, or end of string if (quoting) { // In quoting mode // If we've found a quote character, see if it's // followed by a second quote. If so, then we need // to actually put the quote character into the token // rather than end the token. if (isQuote(srcChars, pos, len, quoteStart, quoteLen)) { if (isQuote(srcChars, pos + quoteLen, len, quoteStart, quoteLen)) { // matched pair of quotes, thus an escaped quote workArea.append(srcChars, pos, quoteLen); pos += quoteLen * 2; trimStart = workArea.size(); continue; } // end of quoting quoting = false; pos += quoteLen; continue; } } else { // Not in quoting mode // check for delimiter, and thus end of token final int delimLen = getDelimiterMatcher().isMatch(srcChars, pos, start, len); if (delimLen > 0) { // return condition when end of token found addToken(tokenList, workArea.substring(0, trimStart)); return pos + delimLen; } // check for quote, and thus back into quoting mode if (quoteLen > 0 && isQuote(srcChars, pos, len, quoteStart, quoteLen)) { quoting = true; pos += quoteLen; continue; } // check for ignored (outside quotes), and ignore final int ignoredLen = getIgnoredMatcher().isMatch(srcChars, pos, start, len); if (ignoredLen > 0) { pos += ignoredLen; continue; } // check for trimmed character // don't yet know if its at the end, so copy to workArea // use trimStart to keep track of trim at the end final int trimmedLen = getTrimmerMatcher().isMatch(srcChars, pos, start, len); if (trimmedLen > 0) { workArea.append(srcChars, pos, trimmedLen); pos += trimmedLen; continue; } } // copy regular character from inside quotes workArea.append(srcChars[pos++]); trimStart = workArea.size(); } // return condition when end of string found addToken(tokenList, workArea.substring(0, trimStart)); return -1; } /** * Unsupported ListIterator operation. * * @throws UnsupportedOperationException always. */ @Override public void remove() { throw new UnsupportedOperationException("remove() is unsupported"); } /** * Resets this tokenizer, forgetting all parsing and iteration already completed. *

* This method allows the same tokenizer to be reused for the same String. *

* * @return {@code this} instance. */ public StrTokenizer reset() { tokenPos = 0; tokens = null; return this; } /** * Reset this tokenizer, giving it a new input string to parse. In this manner you can re-use a tokenizer with the same settings on multiple input lines. * * @param input the new character array to tokenize, not cloned, null sets no text to parse. * @return {@code this} instance. */ public StrTokenizer reset(final char[] input) { reset(); if (input != null) { this.chars = input.clone(); } else { this.chars = null; } return this; } /** * Reset this tokenizer, giving it a new input string to parse. In this manner you can re-use a tokenizer with the same settings on multiple input lines. * * @param input the new string to tokenize, null sets no text to parse. * @return {@code this} instance. */ public StrTokenizer reset(final String input) { reset(); if (input != null) { this.chars = input.toCharArray(); } else { this.chars = null; } return this; } /** * Unsupported ListIterator operation. * * @param obj this parameter ignored. * @throws UnsupportedOperationException Always thrown. */ @Override public void set(final String obj) { throw new UnsupportedOperationException("set() is unsupported"); } /** * Sets the field delimiter character. * * @param delim the delimiter character to use. * @return {@code this} instance. */ public StrTokenizer setDelimiterChar(final char delim) { return setDelimiterMatcher(StrMatcher.charMatcher(delim)); } /** * Sets the field delimiter matcher. *

* The delimiter is used to separate one token from another. *

* * @param delim the delimiter matcher to use. * @return {@code this} instance. */ public StrTokenizer setDelimiterMatcher(final StrMatcher delim) { if (delim == null) { this.delimMatcher = StrMatcher.noneMatcher(); } else { this.delimMatcher = delim; } return this; } /** * Sets the field delimiter string. * * @param delim the delimiter string to use. * @return {@code this} instance. */ public StrTokenizer setDelimiterString(final String delim) { return setDelimiterMatcher(StrMatcher.stringMatcher(delim)); } /** * Sets whether the tokenizer should return empty tokens as null. The default for this property is false. * * @param emptyAsNull whether empty tokens are returned as null. * @return {@code this} instance. */ public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) { this.emptyAsNull = emptyAsNull; return this; } /** * Sets the character to ignore. *

* This character is ignored when parsing the String, unless it is within a quoted region. *

* * @param ignored the ignored character to use. * @return {@code this} instance. */ public StrTokenizer setIgnoredChar(final char ignored) { return setIgnoredMatcher(StrMatcher.charMatcher(ignored)); } /** * Sets the matcher for characters to ignore. *

* These characters are ignored when parsing the String, unless they are within a quoted region. *

* * @param ignored the ignored matcher to use, null ignored. * @return {@code this} instance. */ public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) { if (ignored != null) { this.ignoredMatcher = ignored; } return this; } /** * Sets whether the tokenizer should ignore and not return empty tokens. The default for this property is true. * * @param ignoreEmptyTokens whether empty tokens are not returned. * @return {@code this} instance. */ public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) { this.ignoreEmptyTokens = ignoreEmptyTokens; return this; } /** * Sets the quote character to use. *

* The quote character is used to wrap data between the tokens. This enables delimiters to be entered as data. *

* * @param quote the quote character to use. * @return {@code this} instance. */ public StrTokenizer setQuoteChar(final char quote) { return setQuoteMatcher(StrMatcher.charMatcher(quote)); } /** * Sets the quote matcher to use. *

* The quote character is used to wrap data between the tokens. This enables delimiters to be entered as data. *

* * @param quote the quote matcher to use, null ignored. * @return {@code this} instance. */ public StrTokenizer setQuoteMatcher(final StrMatcher quote) { if (quote != null) { this.quoteMatcher = quote; } return this; } /** * Sets the matcher for characters to trim. *

* These characters are trimmed off on each side of the delimiter until the token or quote is found. *

* * @param trimmer the trimmer matcher to use, null ignored * @return {@code this} instance. */ public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) { if (trimmer != null) { this.trimmerMatcher = trimmer; } return this; } /** * Gets the number of tokens found in the String. * * @return The number of matched tokens. */ public int size() { checkTokenized(); return tokens.length; } /** * Internal method to performs the tokenization. *

* Most users of this class do not need to call this method. This method will be called automatically by other (public) methods when required. *

*

* This method exists to allow subclasses to add code before or after the tokenization. For example, a subclass could alter the character array, offset or * count to be parsed, or call the tokenizer multiple times on multiple strings. It is also be possible to filter the results. *

*

* {@code StrTokenizer} will always pass a zero offset and a count equal to the length of the array to this method, however a subclass may pass other * values, or even an entirely different array. *

* * @param srcChars the character array being tokenized, may be null. * @param offset the start position within the character array, must be valid. * @param count the number of characters to tokenize, must be valid. * @return The modifiable list of String tokens, unmodifiable if null array or zero count. */ protected List tokenize(final char[] srcChars, final int offset, final int count) { if (srcChars == null || count == 0) { return Collections.emptyList(); } final StrBuilder buf = new StrBuilder(); final List tokenList = new ArrayList<>(); int pos = offset; // loop around the entire buffer while (pos >= 0 && pos < count) { // find next token pos = readNextToken(srcChars, pos, count, buf, tokenList); // handle case where end of string is a delimiter if (pos >= count) { addToken(tokenList, StringUtils.EMPTY); } } return tokenList; } /** * Gets the String content that the tokenizer is parsing. * * @return The string content being parsed. */ @Override public String toString() { if (tokens == null) { return "StrTokenizer[not tokenized yet]"; } return "StrTokenizer" + getTokenList(); } } commons-text-rel-commons-text-1.15.0/src/main/java/org/apache/commons/text/StringEscapeUtils.java000066400000000000000000001032571511432740600330370ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import java.io.IOException; import java.io.Writer; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.translate.AggregateTranslator; import org.apache.commons.text.translate.CharSequenceTranslator; import org.apache.commons.text.translate.CsvTranslators; import org.apache.commons.text.translate.EntityArrays; import org.apache.commons.text.translate.JavaUnicodeEscaper; import org.apache.commons.text.translate.LookupTranslator; import org.apache.commons.text.translate.NumericEntityEscaper; import org.apache.commons.text.translate.NumericEntityUnescaper; import org.apache.commons.text.translate.OctalUnescaper; import org.apache.commons.text.translate.UnicodeUnescaper; import org.apache.commons.text.translate.UnicodeUnpairedSurrogateRemover; /** *

* Escapes and unescapes {@code String}s for Java, Java Script, HTML and XML. *

* *

* #ThreadSafe# *

* *

* This code has been adapted from Apache Commons Lang 3.5. *

* * @since 1.0 */ public class StringEscapeUtils { /* ESCAPE TRANSLATORS */ /** * Convenience wrapper for {@link StringBuilder} providing escape methods. * *

Example:

*
     * new Builder(ESCAPE_HTML4)
     *      .append("<p>")
     *      .escape("This is paragraph 1 and special chars like & get escaped.")
     *      .append("</p><p>")
     *      .escape("This is paragraph 2 & more...")
     *      .append("</p>")
     *      .toString()
     * 
*/ public static final class Builder { /** * StringBuilder to be used in the Builder class. */ private final StringBuilder sb; /** * CharSequenceTranslator to be used in the Builder class. */ private final CharSequenceTranslator translator; /** * Builder constructor. * * @param translator a CharSequenceTranslator. */ private Builder(final CharSequenceTranslator translator) { this.sb = new StringBuilder(); this.translator = translator; } /** * Literal append, no escaping being done. * * @param input the String to append * @return {@code this}, to enable chaining */ public Builder append(final String input) { sb.append(input); return this; } /** * Escape {@code input} according to the given {@link CharSequenceTranslator}. * * @param input the String to escape * @return {@code this}, to enable chaining */ public Builder escape(final String input) { sb.append(translator.translate(input)); return this; } /** * Return the escaped string. * * @return The escaped string */ @Override public String toString() { return sb.toString(); } } /** * Translator object for unescaping backslash escaped entries. */ static class XsiUnescaper extends CharSequenceTranslator { /** * Escaped backslash constant. */ private static final char BACKSLASH = '\\'; @Override public int translate(final CharSequence input, final int index, final Writer writer) throws IOException { if (index != 0) { throw new IllegalStateException("XsiUnescaper should never reach the [1] index"); } final String s = input.toString(); int segmentStart = 0; int searchOffset = 0; while (true) { final int pos = s.indexOf(BACKSLASH, searchOffset); if (pos == -1) { if (segmentStart < s.length()) { writer.write(s.substring(segmentStart)); } break; } if (pos > segmentStart) { writer.write(s.substring(segmentStart, pos)); } segmentStart = pos + 1; searchOffset = pos + 2; } return Character.codePointCount(input, 0, input.length()); } } /** * Translator object for escaping Java. * * While {@link #escapeJava(String)} is the expected method of use, this object allows the Java escaping functionality to be used as the foundation for a * custom translator. */ public static final CharSequenceTranslator ESCAPE_JAVA; static { final Map escapeJavaMap = new HashMap<>(); escapeJavaMap.put("\"", "\\\""); escapeJavaMap.put("\\", "\\\\"); ESCAPE_JAVA = new AggregateTranslator( new LookupTranslator(Collections.unmodifiableMap(escapeJavaMap)), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE), JavaUnicodeEscaper.outsideOf(32, 0x7f) ); } /** * Translator object for escaping EcmaScript/JavaScript. * * While {@link #escapeEcmaScript(String)} is the expected method of use, this object allows the EcmaScript escaping functionality to be used as the * foundation for a custom translator. */ public static final CharSequenceTranslator ESCAPE_ECMASCRIPT; static { final Map escapeEcmaScriptMap = new HashMap<>(); escapeEcmaScriptMap.put("'", "\\'"); escapeEcmaScriptMap.put("\"", "\\\""); escapeEcmaScriptMap.put("\\", "\\\\"); escapeEcmaScriptMap.put("/", "\\/"); ESCAPE_ECMASCRIPT = new AggregateTranslator( new LookupTranslator(Collections.unmodifiableMap(escapeEcmaScriptMap)), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE), JavaUnicodeEscaper.outsideOf(32, 0x7f) ); } /** * Translator object for escaping Json. * * While {@link #escapeJson(String)} is the expected method of use, this object allows the Json escaping functionality to be used as the foundation for a * custom translator. */ public static final CharSequenceTranslator ESCAPE_JSON; static { final Map escapeJsonMap = new HashMap<>(); escapeJsonMap.put("\"", "\\\""); escapeJsonMap.put("\\", "\\\\"); escapeJsonMap.put("/", "\\/"); ESCAPE_JSON = new AggregateTranslator( new LookupTranslator(Collections.unmodifiableMap(escapeJsonMap)), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE), JavaUnicodeEscaper.outsideOf(32, 0x7e) ); } /** * Translator object for escaping XML 1.0. * * While {@link #escapeXml10(String)} is the expected method of use, this object allows the XML escaping functionality to be used as the foundation for a * custom translator. */ public static final CharSequenceTranslator ESCAPE_XML10; static { final Map escapeXml10Map = new HashMap<>(); escapeXml10Map.put("\u0000", StringUtils.EMPTY); escapeXml10Map.put("\u0001", StringUtils.EMPTY); escapeXml10Map.put("\u0002", StringUtils.EMPTY); escapeXml10Map.put("\u0003", StringUtils.EMPTY); escapeXml10Map.put("\u0004", StringUtils.EMPTY); escapeXml10Map.put("\u0005", StringUtils.EMPTY); escapeXml10Map.put("\u0006", StringUtils.EMPTY); escapeXml10Map.put("\u0007", StringUtils.EMPTY); escapeXml10Map.put("\u0008", StringUtils.EMPTY); escapeXml10Map.put("\u000b", StringUtils.EMPTY); escapeXml10Map.put("\u000c", StringUtils.EMPTY); escapeXml10Map.put("\u000e", StringUtils.EMPTY); escapeXml10Map.put("\u000f", StringUtils.EMPTY); escapeXml10Map.put("\u0010", StringUtils.EMPTY); escapeXml10Map.put("\u0011", StringUtils.EMPTY); escapeXml10Map.put("\u0012", StringUtils.EMPTY); escapeXml10Map.put("\u0013", StringUtils.EMPTY); escapeXml10Map.put("\u0014", StringUtils.EMPTY); escapeXml10Map.put("\u0015", StringUtils.EMPTY); escapeXml10Map.put("\u0016", StringUtils.EMPTY); escapeXml10Map.put("\u0017", StringUtils.EMPTY); escapeXml10Map.put("\u0018", StringUtils.EMPTY); escapeXml10Map.put("\u0019", StringUtils.EMPTY); escapeXml10Map.put("\u001a", StringUtils.EMPTY); escapeXml10Map.put("\u001b", StringUtils.EMPTY); escapeXml10Map.put("\u001c", StringUtils.EMPTY); escapeXml10Map.put("\u001d", StringUtils.EMPTY); escapeXml10Map.put("\u001e", StringUtils.EMPTY); escapeXml10Map.put("\u001f", StringUtils.EMPTY); escapeXml10Map.put("\ufffe", StringUtils.EMPTY); escapeXml10Map.put("\uffff", StringUtils.EMPTY); ESCAPE_XML10 = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_ESCAPE), new LookupTranslator(EntityArrays.APOS_ESCAPE), new LookupTranslator(Collections.unmodifiableMap(escapeXml10Map)), NumericEntityEscaper.between(0x7f, 0x84), NumericEntityEscaper.between(0x86, 0x9f), new UnicodeUnpairedSurrogateRemover() ); } /** * Translator object for escaping XML 1.1. * * While {@link #escapeXml11(String)} is the expected method of use, this * object allows the XML escaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator ESCAPE_XML11; static { final Map escapeXml11Map = new HashMap<>(); escapeXml11Map.put("\u0000", StringUtils.EMPTY); escapeXml11Map.put("\u000b", " "); escapeXml11Map.put("\u000c", " "); escapeXml11Map.put("\ufffe", StringUtils.EMPTY); escapeXml11Map.put("\uffff", StringUtils.EMPTY); ESCAPE_XML11 = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_ESCAPE), new LookupTranslator(EntityArrays.APOS_ESCAPE), new LookupTranslator(Collections.unmodifiableMap(escapeXml11Map)), NumericEntityEscaper.between(0x1, 0x8), NumericEntityEscaper.between(0xe, 0x1f), NumericEntityEscaper.between(0x7f, 0x84), NumericEntityEscaper.between(0x86, 0x9f), new UnicodeUnpairedSurrogateRemover() ); } /** * Translator object for escaping HTML version 3.0. * * While {@link #escapeHtml3(String)} is the expected method of use, this * object allows the HTML escaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator ESCAPE_HTML3 = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_ESCAPE), new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE) ); /** * Translator object for escaping HTML version 4.0. * * While {@link #escapeHtml4(String)} is the expected method of use, this * object allows the HTML escaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator ESCAPE_HTML4 = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_ESCAPE), new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE), new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE) ); /** * Translator object for escaping individual Comma Separated Values. * * While {@link #escapeCsv(String)} is the expected method of use, this * object allows the CSV escaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator ESCAPE_CSV = new CsvTranslators.CsvEscaper(); /* UNESCAPE TRANSLATORS */ /** * Translator object for escaping Shell command language. * * @see Shell Command Language */ public static final CharSequenceTranslator ESCAPE_XSI; static { final Map escapeXsiMap = new HashMap<>(); escapeXsiMap.put("|", "\\|"); escapeXsiMap.put("&", "\\&"); escapeXsiMap.put(";", "\\;"); escapeXsiMap.put("<", "\\<"); escapeXsiMap.put(">", "\\>"); escapeXsiMap.put("(", "\\("); escapeXsiMap.put(")", "\\)"); escapeXsiMap.put("$", "\\$"); escapeXsiMap.put("`", "\\`"); escapeXsiMap.put("\\", "\\\\"); escapeXsiMap.put("\"", "\\\""); escapeXsiMap.put("'", "\\'"); escapeXsiMap.put(" ", "\\ "); escapeXsiMap.put("\t", "\\\t"); escapeXsiMap.put("\r\n", StringUtils.EMPTY); escapeXsiMap.put("\n", StringUtils.EMPTY); escapeXsiMap.put("*", "\\*"); escapeXsiMap.put("?", "\\?"); escapeXsiMap.put("[", "\\["); escapeXsiMap.put("#", "\\#"); escapeXsiMap.put("~", "\\~"); escapeXsiMap.put("=", "\\="); escapeXsiMap.put("%", "\\%"); ESCAPE_XSI = new LookupTranslator( Collections.unmodifiableMap(escapeXsiMap) ); } /** * Translator object for unescaping escaped Java. * * While {@link #unescapeJava(String)} is the expected method of use, this * object allows the Java unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_JAVA; static { final Map unescapeJavaMap = new HashMap<>(); unescapeJavaMap.put("\\\\", "\\"); unescapeJavaMap.put("\\\"", "\""); unescapeJavaMap.put("\\'", "'"); unescapeJavaMap.put("\\", StringUtils.EMPTY); UNESCAPE_JAVA = new AggregateTranslator( new OctalUnescaper(), // .between('\1', '\377'), new UnicodeUnescaper(), new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE), new LookupTranslator(Collections.unmodifiableMap(unescapeJavaMap)) ); } /** * Translator object for unescaping escaped EcmaScript. * * While {@link #unescapeEcmaScript(String)} is the expected method of use, this * object allows the EcmaScript unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA; /** * Translator object for unescaping escaped Json. * * While {@link #unescapeJson(String)} is the expected method of use, this * object allows the Json unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA; /** * Translator object for unescaping escaped HTML 3.0. * * While {@link #unescapeHtml3(String)} is the expected method of use, this * object allows the HTML unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_HTML3 = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_UNESCAPE), new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE), new NumericEntityUnescaper() ); /** * Translator object for unescaping escaped HTML 4.0. * * While {@link #unescapeHtml4(String)} is the expected method of use, this * object allows the HTML unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_HTML4 = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_UNESCAPE), new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE), new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE), new NumericEntityUnescaper() ); /** * Translator object for unescaping escaped XML. * * While {@link #unescapeXml(String)} is the expected method of use, this * object allows the XML unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_XML = new AggregateTranslator( new LookupTranslator(EntityArrays.BASIC_UNESCAPE), new LookupTranslator(EntityArrays.APOS_UNESCAPE), new NumericEntityUnescaper() ); /** * Translator object for unescaping escaped Comma Separated Value entries. * * While {@link #unescapeCsv(String)} is the expected method of use, this * object allows the CSV unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_CSV = new CsvTranslators.CsvUnescaper(); /* Helper functions */ /** * Translator object for unescaping escaped XSI Value entries. * * While {@link #unescapeXSI(String)} is the expected method of use, this * object allows the XSI unescaping functionality to be used * as the foundation for a custom translator. */ public static final CharSequenceTranslator UNESCAPE_XSI = new XsiUnescaper(); /** * Gets a {@link Builder}. * * @param translator the text translator. * @return {@link Builder} */ public static StringEscapeUtils.Builder builder(final CharSequenceTranslator translator) { return new Builder(translator); } /** * Returns a {@code String} value for a CSV column enclosed in double quotes, if required. * *

* If the value contains a comma, newline or double quote, then the String value is returned enclosed in double quotes. *

* *

* Any double quote characters in the value are escaped with another double quote. *

* *

* If the value does not contain a comma, newline or double quote, then the String value is returned unchanged. *

*

* See Wikipedia and RFC 4180. *

* * @param input the input CSV column String, may be null. * @return The input String, enclosed in double quotes if the value contains a comma, newline or double quote, {@code null} if null string input. */ public static String escapeCsv(final String input) { return ESCAPE_CSV.translate(input); } /** * Escapes the characters in a {@code String} using EcmaScript String rules. * *

* Escapes any values it finds into their EcmaScript String form. Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) *

* *

* So a tab becomes the characters {@code '\\'} and {@code 't'}. *

* *

* The only difference between Java strings and EcmaScript strings is that in EcmaScript, a single quote and forward-slash (/) are escaped. *

* *

* Note that EcmaScript is best known by the JavaScript and ActionScript dialects. *

* *

* Example: *

* *
     * input string: He didn't say, "Stop!"
     * output string: He didn\'t say, \"Stop!\"
     * 
*

* Security Note. We only provide backslash escaping in this method. For example, {@code '\"'} has the output {@code '\\\"'} which could * result in potential issues in the case where the string being escaped is being used in an HTML tag like {@code [if-any http] [for http][end] [end] [if-any ftp] [for ftp][end] [end] [if-any backup] [for backup][end] [end]

It is essential that you verify the integrity of downloaded files, preferably using the PGP signature (*.asc files); failing that using the SHA512 hash (*.sha512 checksum files).

The KEYS file contains the public PGP keys used by Apache Commons developers to sign releases.

commons-text-1.15.0-bin.tar.gz sha512 pgp
commons-text-1.15.0-bin.zip sha512 pgp
commons-text-1.15.0-src.tar.gz sha512 pgp
commons-text-1.15.0-src.zip sha512 pgp

Older releases can be obtained from the archives.

commons-text-rel-commons-text-1.15.0/src/site/xdoc/index.xml000066400000000000000000000077321511432740600240030ustar00rootroot00000000000000 Home Apache Commons Team

Apache Commons Text is a library focused on algorithms working on strings.

We provide documentation in the form of a User Guide, Javadoc, and Project Reports.

The Git repository can be browsed, or you can browse/contribute via GitHub.

Download the latest release from dependency-info.html

Alternatively, you can use a build tool dependency.

For information on previous releases see the Release History, and to download previous releases see the Commons Text Archive.

The commons developer mailing list is the main channel of communication for contributors. Please remember that the lists are shared between all commons components, so prefix your email by [text].

You can also peruse JIRA. Specific links of interest for JIRA are:

Alternatively you can go through the Needs Work tags in the TagList report.

If you'd like to offer up pull requests via GitHub rather than applying patches to JIRA, we have a GitHub mirror.

The commons mailing lists act as the main support forum. The user list is suitable for most library usage queries. The dev list is intended for the development discussion. Please remember that the lists are shared between all commons components, so prefix your email by [text].

Bug reports and enhancements are also welcomed via the JIRA issue tracker. Please read the instructions carefully.

commons-text-rel-commons-text-1.15.0/src/site/xdoc/issue-tracking.xml000066400000000000000000000136111511432740600256150ustar00rootroot00000000000000 Apache Commons Text Issue tracking Apache Commons Team

Apache Commons Text uses ASF JIRA for tracking issues. See the Apache Commons Text JIRA project page.

To use JIRA you may need to create an account (if you have previously created/updated Commons issues using Bugzilla an account will have been automatically created and you can use the Forgot Password page to get a new password).

If you would like to report a bug, or raise an enhancement request with Apache Commons Text please do the following:

  1. Search existing open bugs. If you find your issue listed then please add a comment with your details.
  2. Search the mailing list archive(s). You may find your issue or idea has already been discussed.
  3. Decide if your issue is a bug or an enhancement.
  4. Submit either a bug report or enhancement request.

Please also remember these points:

  • the more information you provide, the better we can help you
  • test cases are vital, particularly for any proposed enhancements
  • the developers of Apache Commons Text are all unpaid volunteers

For more information on creating patches see the Apache Contributors Guide.

You may also find these links useful:

commons-text-rel-commons-text-1.15.0/src/site/xdoc/mail-lists.xml000066400000000000000000000216071511432740600247470ustar00rootroot00000000000000 Apache Commons Text Mailing Lists Apache Commons Team

Apache Commons Text shares mailing lists with all the other Commons Components. To make it easier for people to only read messages related to components they are interested in, the convention in Commons is to prefix the subject line of messages with the component's name, for example:

  • [text] Problem with the ...

Questions related to the usage of Apache Commons Text should be posted to the User List.
The Developer List is for questions and discussion related to the development of Apache Commons Text.
Please do not cross-post; developers are also subscribed to the user list.
You must be subscribed to post to the mailing lists. Follow the Subscribe links below to subscribe.

Note: please don't send patches or attachments to any of the mailing lists; most of the lists are set up to drop attachments. Patches are best handled via the Issue Tracking system. If you have a GitHub account, most components also accept PRs (pull requests). Otherwise, please upload the file to a public server and include the URL in the mail.

Please prefix the subject line of any messages for Apache Commons Text with [text] - thanks!

Name Subscribe Unsubscribe Post Archive Other Archives
Commons User List

Questions on using Apache Commons Text.

Subscribe Unsubscribe Post lists.apache.org www.mail-archive.com
Commons Developer List

Discussion of development of Apache Commons Text.

Subscribe Unsubscribe Post lists.apache.org www.mail-archive.com
Commons Issues List

Only for e-mails automatically generated by the issue tracking system.

Subscribe Unsubscribe read only lists.apache.org www.mail-archive.com
Commons Commits List

Only for e-mails automatically generated by the source control system.

Subscribe Unsubscribe read only lists.apache.org www.mail-archive.com

Other mailing lists which you may find useful include:

Name Subscribe Unsubscribe Post Archive Other Archives
Apache Announce List

General announcements of Apache project releases.

Subscribe Unsubscribe read only lists.apache.org www.mail-archive.com
commons-text-rel-commons-text-1.15.0/src/site/xdoc/proposal.xml000066400000000000000000000057301511432740600245270ustar00rootroot00000000000000 Proposal for Apache Commons Text Package

Providing algorithms for processing texts like editing distance or similarity is out of scope of the standard Java libraries. The Commons Text Package provides these extra methods.

This proposal is to create a package of Java utility classes implementing well known string algorithms and metrics.

Commons Text relies only on standard JDK 7 (or later) APIs for production deployment. It utilizes the JUnit unit testing framework and the hamcrest matcher library for developing and executing unit tests, but this is of interest only to developers of the component. Commons Text may be a dependency for several existing components in the open source world that implement higher order text processing.

No external configuration files are utilized.

The initial classes came from the Commons Lang and Commons Codec subprojects.

The proposed package name for the new component is org.apache.commons.text.

  • Git Repository - New repository commons-text.
  • Mailing List - Discussions will take place on the general dev@commons.apache.org mailing list. To help list subscribers identify messages of interest, it is suggested that the message subject of messages about this component be prefixed with [text].
  • Jira - New component "Common Text" under the "Commons Sandbox" product.
  • Confluence FAQ - New category "commons-text" (when available).

The initial committers on the Commons Text component shall be as follows:

  • Benedikt Ritter (britter)
  • Bruno P. Kinoshita (kinow)

commons-text-rel-commons-text-1.15.0/src/site/xdoc/security.xml000066400000000000000000000155771511432740600245510ustar00rootroot00000000000000 Apache Commons Text Security Reports Commons Team

For information about reporting or asking questions about security, please see the security page of the Apache Commons project.

This page lists all security vulnerabilities fixed in released versions of this component.

Please note that binary patches are never provided. If you need to apply a source code patch, use the building instructions for the component version that you are using.

If you need help on building this component or other help on following the instructions to mitigate the known vulnerabilities listed here, please send your questions to the public user mailing list .

If you have encountered an unlisted security vulnerability or other unexpected behavior that has security impact, or if the descriptions here are incomplete, please report them privately to the Apache Security Team. Thank you.

On 2022-10-13, the Apache Commons Text team disclosed CVE-2022-42889 . Key takeaways:

  • If you rely on software that uses a version of commons-text prior to 1.10.0, you are likely still not vulnerable: only if this software uses the StringSubstitutor API without properly sanitizing any untrusted input.
  • If your own software uses commons-text, double-check whether it uses the StringSubstitutor API without properly sanitizing any untrusted input. If so, an update to 1.10.0 could be a quick workaround, but the recommended solution is to also properly validate and sanitize any untrusted input.

Apache Commons Text is a low-level library for performing various text operations, such as escaping, calculating string differences, and substituting placeholders in the text with values looked up through interpolators. When using the string substitution feature, some of the available interpolators can trigger network access or code execution. This is intended, but it also means an application that includes user input in the string passed to the substitution without properly sanitizing it would allow an attacker to trigger those interpolators.

For that reason the Apache Commons Text team have decided to update the configuration to be more "secure by default", so that the impact of a failure to validate inputs is mitigated and will not give an attacker access to these interpolators. However, it is still recommended that users treat untrusted input with care.

We're not currently aware of any applications that pass untrusted input to the substitutor and thus would have been impacted by this problem prior to Apache Commons Text 1.10.0.

This issue is different from Log4Shell (CVE-2021-44228) because in Log4Shell, string interpolation was possible from the log message body, which commonly contains untrusted input. In the Apache Common Text issue, the relevant method is explicitly intended and clearly documented to perform string interpolation, so it is much less likely that applications would inadvertently pass in untrusted input without proper validation.

Credit: this issue was reported independently by Ruilin and by @pwntester (Alvaro Muñoz) of the GitHub Security Lab team . Thank you!

References:

commons-text-rel-commons-text-1.15.0/src/test/000077500000000000000000000000001511432740600212175ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/000077500000000000000000000000001511432740600221405ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/000077500000000000000000000000001511432740600227275ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/000077500000000000000000000000001511432740600241505ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/000077500000000000000000000000001511432740600256235ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/000077500000000000000000000000001511432740600266075ustar00rootroot00000000000000AlphabetConverterTest.java000066400000000000000000000340241511432740600336460ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.Test; /** * Tests {@link AlphabetConverter}. */ class AlphabetConverterTest { private static final Character[] LOWER_CASE_ENGLISH = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; private static final Character[] ENGLISH_AND_NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ' }; private static final Character[] LOWER_CASE_ENGLISH_AND_NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ' }; private static final Character[] NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; private static final Character[] BINARY = { '0', '1' }; private static final Character[] HEBREW = { '_', ' ', '\u05e7', '\u05e8', '\u05d0', '\u05d8', '\u05d5', '\u05df', '\u05dd', '\u05e4', '\u05e9', '\u05d3', '\u05d2', '\u05db', '\u05e2', '\u05d9', '\u05d7', '\u05dc', '\u05da', '\u05e3', '\u05d6', '\u05e1', '\u05d1', '\u05d4', '\u05e0', '\u05de', '\u05e6', '\u05ea', '\u05e5' }; private static final Integer[] UNICODE = { 32, 35395, 35397, 36302, 36291, 35203, 35201, 35215, 35219, 35268, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 1001, 1002, 1003, 1004, 1005 }; private static final Integer[] LOWER_CASE_ENGLISH_CODEPOINTS = { 32, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 }; private static final Integer[] DO_NOT_ENCODE_CODEPOINTS = { 32, 97, 98, 99 }; // space, a, b, c private AlphabetConverter createJavadocExample() { final Character[] original = { 'a', 'b', 'c', 'd' }; final Character[] encoding = { '0', '1', 'd' }; final Character[] doNotEncode = { 'd' }; return AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); } private void test(final Character[] originalChars, final Character[] encodingChars, final Character[] doNotEncodeChars, final String... strings) throws UnsupportedEncodingException { final AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originalChars, encodingChars, doNotEncodeChars); final AlphabetConverter reconstructedAlphabetConverter = AlphabetConverter.createConverterFromMap(ac.getOriginalToEncoded()); assertEquals(ac, reconstructedAlphabetConverter); assertEquals(ac.hashCode(), reconstructedAlphabetConverter.hashCode()); assertEquals(ac.toString(), reconstructedAlphabetConverter.toString()); assertNull(ac.encode(null)); // test null conversions assertEquals("", ac.encode("")); // test empty conversion // test all the trial strings for (final String s : strings) { final String encoded = ac.encode(s); // test that only encoding chars are used final List originalEncodingChars = Arrays.asList(encodingChars); for (int i = 0; i < encoded.length(); i++) { assertTrue(originalEncodingChars.contains(encoded.charAt(i))); } final String decoded = ac.decode(encoded); // test that only the original alphabet is used after decoding final List originalCharsList = Arrays.asList(originalChars); for (int i = 0; i < decoded.length(); i++) { assertTrue(originalCharsList.contains(decoded.charAt(i))); } assertEquals(s, decoded, () -> "Encoded '" + s + "' into '" + encoded + "', but decoded into '" + decoded + "'"); } } @Test void testBinaryTest() throws UnsupportedEncodingException { test(BINARY, NUMBERS, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "0", "1", "10", "11"); test(NUMBERS, BINARY, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "12345", "0"); test(LOWER_CASE_ENGLISH, BINARY, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "abc", "a"); } @Test void testCreateConverterFromCharsAndEquals() { final Character[] characterArray = new Character[2]; final char charOne = '+'; final char character = '+'; characterArray[0] = character; characterArray[1] = characterArray[0]; final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray); assertFalse(alphabetConverter.equals(charOne)); } @Test void testCreateConverterFromCharsOne() { final Character[] characterArray = new Character[2]; characterArray[0] = '5'; characterArray[1] = characterArray[0]; final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray); assertEquals(1, alphabetConverter.getEncodedCharLength()); } @Test void testCreateConverterFromCharsWithNullAndNull() { assertThrows(IllegalArgumentException.class, () -> { final Character[] characterArray = new Character[2]; characterArray[0] = '$'; characterArray[1] = characterArray[0]; AlphabetConverter.createConverterFromChars(characterArray, null, null); }); } @Test void testCreateConverterFromMapAndEquals() { final Map hashMap = new HashMap<>(); final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(hashMap); hashMap.put(0, "CtDs"); final AlphabetConverter alphabetConverterTwo = AlphabetConverter.createConverterFromMap(hashMap); assertFalse(alphabetConverter.equals(alphabetConverterTwo)); assertEquals(1, alphabetConverter.getEncodedCharLength()); } @Test void testDecodeReturningNull() throws UnsupportedEncodingException { final Map map = new HashMap<>(); final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(map); alphabetConverter.decode(null); assertEquals(1, alphabetConverter.getEncodedCharLength()); } @Test void testDoNotEncodeTest() throws UnsupportedEncodingException { test(ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH, "1", "456", "abc", "ABC", "this will not be converted but THIS WILL"); test(ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH_AND_NUMBERS, NUMBERS, "1", "456", "abc", "ABC", "this will be converted but 12345 and this will be"); } @Test void testEncodeFailureTest() { assertEquals("Couldn't find encoding for '3' in 3", assertThrows(UnsupportedEncodingException.class, () -> test(BINARY, NUMBERS, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "3")).getMessage()); } @Test void testEquals() { final Character[] characterArray = new Character[2]; final char character = 'R'; characterArray[0] = character; characterArray[1] = character; final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray); final Map map = new HashMap<>(); final AlphabetConverter alphabetConverterTwo = AlphabetConverter.createConverterFromMap(map); assertEquals(1, alphabetConverterTwo.getEncodedCharLength()); assertFalse(alphabetConverter.equals(alphabetConverterTwo)); } @Test void testEqualsWithNull() { final Character[] characterArray = ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY; final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, null, null); assertFalse(alphabetConverter.equals(null)); } @Test void testEqualsWithSameObject() { final Character[] characterArray = new Character[2]; final char character = 'R'; characterArray[0] = character; characterArray[1] = character; final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray); assertTrue(alphabetConverter.equals(alphabetConverter)); } @Test void testHebrewTest() throws UnsupportedEncodingException { test(HEBREW, BINARY, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "\u05d0", "\u05e2", "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_" + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc"); test(HEBREW, NUMBERS, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "\u05d0", "\u05e2", "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_" + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc"); test(NUMBERS, HEBREW, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "123456789", "1", "5"); test(LOWER_CASE_ENGLISH, HEBREW, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "this is a test"); } /* * Test example in javadocs for consistency */ @Test void testJavadocExampleTest() throws UnsupportedEncodingException { final AlphabetConverter ac = createJavadocExample(); assertEquals("00", ac.encode("a")); assertEquals("01", ac.encode("b")); assertEquals("0d", ac.encode("c")); assertEquals("d", ac.encode("d")); assertEquals("00010dd", ac.encode("abcd")); } @Test void testMissingDoNotEncodeLettersFromEncodingTest() { assertEquals("Can not use 'do not encode' list because encoding alphabet does not contain '0'", assertThrows(IllegalArgumentException.class, () -> AlphabetConverter.createConverterFromChars(ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH, NUMBERS)) .getMessage()); } @Test void testMissingDoNotEncodeLettersFromOriginalTest() { assertEquals("Can not use 'do not encode' list because original alphabet does not contain '0'", assertThrows(IllegalArgumentException.class, () -> AlphabetConverter.createConverterFromChars(LOWER_CASE_ENGLISH, ENGLISH_AND_NUMBERS, NUMBERS)) .getMessage()); } @Test void testNoEncodingLettersTest() { assertEquals("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 0", assertThrows(IllegalArgumentException.class, () -> AlphabetConverter.createConverterFromChars(ENGLISH_AND_NUMBERS, NUMBERS, NUMBERS)) .getMessage()); } @Test void testOnlyOneEncodingLettersTest() { assertEquals("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 1", assertThrows(IllegalArgumentException.class, () -> { final Character[] numbersPlusUnderscore = Arrays.copyOf(NUMBERS, NUMBERS.length + 1); numbersPlusUnderscore[numbersPlusUnderscore.length - 1] = '_'; AlphabetConverter.createConverterFromChars(ENGLISH_AND_NUMBERS, numbersPlusUnderscore, NUMBERS); }).getMessage()); } @Test void testUnexpectedEndWhileDecodingTest() { final String toDecode = "00d01d0"; assertEquals("Unexpected end of string while decoding " + toDecode, assertThrows(UnsupportedEncodingException.class, () -> createJavadocExample().decode(toDecode)).getMessage()); } @Test void testUnexpectedStringWhileDecodingTest() { final String toDecode = "00XX"; assertEquals("Unexpected string without decoding (XX) in " + toDecode, assertThrows(UnsupportedEncodingException.class, () -> createJavadocExample().decode(toDecode)).getMessage()); } /** * Test constructor from code points */ @Test void testUnicodeTest() throws UnsupportedEncodingException { final AlphabetConverter ac = AlphabetConverter.createConverter(UNICODE, LOWER_CASE_ENGLISH_CODEPOINTS, DO_NOT_ENCODE_CODEPOINTS); assertEquals(2, ac.getEncodedCharLength()); final String original = "\u8a43\u8a45 \u8dce ab \u8dc3 c \u8983"; final String encoded = ac.encode(original); final String decoded = ac.decode(encoded); assertEquals(original, decoded, () -> "Encoded '" + original + "' into '" + encoded + "', but decoded into '" + decoded + "'"); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/CaseUtilsTest.java000066400000000000000000000077661511432740600322260ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import org.junit.jupiter.api.Test; /** * Tests {@link CaseUtils} class. */ class CaseUtilsTest { @Test void testConstructor() { assertNotNull(new CaseUtils()); final Constructor[] cons = CaseUtils.class.getDeclaredConstructors(); assertEquals(1, cons.length); assertTrue(Modifier.isPublic(cons[0].getModifiers())); assertTrue(Modifier.isPublic(CaseUtils.class.getModifiers())); assertFalse(Modifier.isFinal(CaseUtils.class.getModifiers())); } @Test void testToCamelCase() { assertNull(CaseUtils.toCamelCase(null, false, null)); assertEquals("", CaseUtils.toCamelCase("", true, null)); assertEquals("", CaseUtils.toCamelCase(" ", false, null)); assertEquals("aBC@def", CaseUtils.toCamelCase("a b c @def", false, null)); assertEquals("ABC@def", CaseUtils.toCamelCase("a b c @def", true)); assertEquals("ABC@def", CaseUtils.toCamelCase("a b c @def", true, '-')); assertEquals("ABC@def", CaseUtils.toCamelCase("a b c @def", true, '-')); final char[] chars = { '-', '+', ' ', '@' }; assertEquals("", CaseUtils.toCamelCase("-+@ ", true, chars)); assertEquals("toCamelCase", CaseUtils.toCamelCase(" to-CAMEL-cASE", false, chars)); assertEquals("ToCamelCase", CaseUtils.toCamelCase("@@@@ to+CAMEL@cASE ", true, chars)); assertEquals("ToCaMeLCase", CaseUtils.toCamelCase("To+CA+ME L@cASE", true, chars)); assertEquals("toCamelCase", CaseUtils.toCamelCase("To.Camel.Case", false, '.')); assertEquals("toCamelCase", CaseUtils.toCamelCase("To.Camel-Case", false, '-', '.')); assertEquals("toCamelCase", CaseUtils.toCamelCase(" to @ Camel case", false, '-', '@')); assertEquals("ToCamelCase", CaseUtils.toCamelCase(" @to @ Camel case", true, '-', '@')); assertEquals("ToCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", true, null)); assertEquals("toCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", false, null)); assertEquals("toCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", false, null)); assertEquals("tocamelcase", CaseUtils.toCamelCase("tocamelcase", false, null)); assertEquals("Tocamelcase", CaseUtils.toCamelCase("tocamelcase", true, null)); assertEquals("tocamelcase", CaseUtils.toCamelCase("Tocamelcase", false, null)); assertEquals("Tocamelcase", CaseUtils.toCamelCase("tocamelcase", true)); assertEquals("tocamelcase", CaseUtils.toCamelCase("tocamelcase", false)); assertEquals("\uD800\uDF00\uD800\uDF02", CaseUtils.toCamelCase("\uD800\uDF00 \uD800\uDF02", true)); assertEquals("\uD800\uDF00\uD800\uDF01\uD800\uDF02\uD800\uDF03", CaseUtils.toCamelCase("\uD800\uDF00\uD800\uDF01\uD800\uDF14\uD800\uDF02\uD800\uDF03", true, '\uD800', '\uDF14')); } } CharacterPredicatesTest.java000066400000000000000000000115211511432740600341330ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; /** * Tests for {@link CharacterPredicates}. */ class CharacterPredicatesTest { @Test void testArabicNumerals() { assertTrue(CharacterPredicates.ARABIC_NUMERALS.test('0')); assertTrue(CharacterPredicates.ARABIC_NUMERALS.test('1')); assertTrue(CharacterPredicates.ARABIC_NUMERALS.test('9')); assertFalse(CharacterPredicates.ARABIC_NUMERALS.test('/')); assertFalse(CharacterPredicates.ARABIC_NUMERALS.test(':')); assertFalse(CharacterPredicates.ARABIC_NUMERALS.test('a')); } @Test void testAsciiAlphaNumerals() { assertTrue(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('a')); assertTrue(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('z')); assertTrue(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('A')); assertTrue(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('Z')); assertTrue(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('0')); assertTrue(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('9')); assertFalse(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('`')); assertFalse(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('{')); assertFalse(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('@')); assertFalse(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('[')); assertFalse(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('/')); assertFalse(CharacterPredicates.ASCII_ALPHA_NUMERALS.test(':')); } @Test void testAsciiLetters() { assertTrue(CharacterPredicates.ASCII_LETTERS.test('a')); assertTrue(CharacterPredicates.ASCII_LETTERS.test('z')); assertTrue(CharacterPredicates.ASCII_LETTERS.test('A')); assertTrue(CharacterPredicates.ASCII_LETTERS.test('Z')); assertFalse(CharacterPredicates.ASCII_LETTERS.test('9')); assertFalse(CharacterPredicates.ASCII_LETTERS.test('`')); assertFalse(CharacterPredicates.ASCII_LETTERS.test('{')); assertFalse(CharacterPredicates.ASCII_LETTERS.test('@')); assertFalse(CharacterPredicates.ASCII_LETTERS.test('[')); } @Test void testAsciiLowercaseLetters() { assertTrue(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('a')); assertTrue(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('z')); assertFalse(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('9')); assertFalse(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('A')); assertFalse(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('Z')); assertFalse(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('`')); assertFalse(CharacterPredicates.ASCII_LOWERCASE_LETTERS.test('{')); } @Test void testAsciiUppercaseLetters() { assertTrue(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('A')); assertTrue(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('Z')); assertFalse(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('9')); assertFalse(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('@')); assertFalse(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('[')); assertFalse(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('a')); assertFalse(CharacterPredicates.ASCII_UPPERCASE_LETTERS.test('z')); } @Test void testDigits() { assertTrue(CharacterPredicates.DIGITS.test('0')); assertTrue(CharacterPredicates.DIGITS.test('9')); assertFalse(CharacterPredicates.DIGITS.test('-')); assertFalse(CharacterPredicates.DIGITS.test('.')); assertFalse(CharacterPredicates.DIGITS.test('L')); } @Test void testLetters() { assertTrue(CharacterPredicates.LETTERS.test('a')); assertTrue(CharacterPredicates.LETTERS.test('Z')); assertFalse(CharacterPredicates.LETTERS.test('1')); assertFalse(CharacterPredicates.LETTERS.test('?')); assertFalse(CharacterPredicates.LETTERS.test('@')); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/CompositeFormatTest.java000066400000000000000000000061621511432740600334320ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import java.text.FieldPosition; import java.text.Format; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Locale; import org.junit.jupiter.api.Test; /** * Tests {@link CompositeFormat}. */ class CompositeFormatTest { /** * Ensures that the parse/format separation is correctly maintained. */ @Test void testCompositeFormat() { final Format parser = new Format() { private static final long serialVersionUID = 1L; @Override public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { throw new UnsupportedOperationException("Not implemented"); } @Override public Object parseObject(final String source, final ParsePosition pos) { return null; // do nothing } }; final Format formatter = new Format() { private static final long serialVersionUID = 1L; @Override public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { return null; // do nothing } @Override public Object parseObject(final String source, final ParsePosition pos) { throw new UnsupportedOperationException("Not implemented"); } }; final CompositeFormat composite = new CompositeFormat(parser, formatter); composite.parseObject("", null); composite.format(new Object(), new StringBuffer(), null); assertEquals(parser, composite.getParser(), "Parser get method incorrectly implemented"); assertEquals(formatter, composite.getFormatter(), "Formatter get method incorrectly implemented"); } @Test void testUsage() throws Exception { final Format f1 = new SimpleDateFormat("MMddyyyy", Locale.ENGLISH); final Format f2 = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH); final CompositeFormat c = new CompositeFormat(f1, f2); final String testString = "January 3, 2005"; assertEquals(testString, c.format(c.parseObject("01032005"))); assertEquals(testString, c.reformat("01032005")); } } ExtendedMessageFormatTest.java000066400000000000000000000563231511432740600344620ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import java.text.DateFormat; import java.text.FieldPosition; import java.text.Format; import java.text.MessageFormat; import java.text.NumberFormat; import java.text.ParsePosition; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test case for {@link ExtendedMessageFormat}. */ class ExtendedMessageFormatTest { /** * {@link Format} implementation which converts to lower case. */ private static final class LowerCaseFormat extends Format { static final Format INSTANCE = new LowerCaseFormat(); static final FormatFactory FACTORY = (n, a, l) -> LowerCaseFormat.INSTANCE; private static final long serialVersionUID = 1L; @Override public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { return toAppendTo.append(((String) obj).toLowerCase(Locale.ROOT)); } @Override public Object parseObject(final String source, final ParsePosition pos) { throw new UnsupportedOperationException(); } } /** * Alternative ExtendedMessageFormat impl. */ private static final class OtherExtendedMessageFormat extends ExtendedMessageFormat { private static final long serialVersionUID = 1L; OtherExtendedMessageFormat(final String pattern, final Locale locale, final Map registry) { super(pattern, locale, registry); } } /** * {@link FormatFactory} implementation to override date format "short" to "default". */ private static final class OverrideShortDateFormatFactory { static final FormatFactory FACTORY = (n, a, l) -> !"short".equals(a) ? null : l == null ? DateFormat.getDateInstance(DateFormat.DEFAULT) : DateFormat.getDateInstance(DateFormat.DEFAULT, l); } /** * {@link Format} implementation which converts to upper case. */ private static final class UpperCaseFormat extends Format { static final Format INSTANCE = new UpperCaseFormat(); static final FormatFactory FACTORY = (n, a, l) -> UpperCaseFormat.INSTANCE; private static final long serialVersionUID = 1L; @Override public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { return toAppendTo.append(((String) obj).toUpperCase(Locale.ROOT)); } @Override public Object parseObject(final String source, final ParsePosition pos) { throw new UnsupportedOperationException(); } } private final Map registry = new HashMap<>(); /** * Create an ExtendedMessageFormat for the specified pattern and locale and check the formatted output matches the expected result for the parameters. * * @param pattern string * @param registryUnused map (currently unused) * @param args Object[] * @param locale Locale */ private void checkBuiltInFormat(final String pattern, final Map registryUnused, final Object[] args, final Locale locale) { final StringBuilder buffer = new StringBuilder(); buffer.append("Pattern=["); buffer.append(pattern); buffer.append("], locale=["); buffer.append(locale); buffer.append("]"); final MessageFormat mf = createMessageFormat(pattern, locale); // System.out.println(buffer + ", result=[" + mf.format(args) +"]"); ExtendedMessageFormat emf = null; if (locale == null) { emf = new ExtendedMessageFormat(pattern); } else { emf = new ExtendedMessageFormat(pattern, locale); } assertEquals(mf.format(args), emf.format(args), "format " + buffer.toString()); assertEquals(mf.toPattern(), emf.toPattern(), "toPattern " + buffer.toString()); } // /** // * Test extended formats with choice format. // * // * NOTE: FAILING - currently sub-formats not supported // */ // void testExtendedWithChoiceFormat() { // String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}"; // ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry); // assertPatterns(null, pattern, emf.toPattern()); // try { // assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), "ONE"})); // assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), "two"})); // } catch (IllegalArgumentException e) { // // currently sub-formats not supported // } // } // /** // * Test mixed extended and built-in formats with choice format. // * // * NOTE: FAILING - currently sub-formats not supported // */ // void testExtendedAndBuiltInWithChoiceFormat() { // String pattern = "Choice: {0,choice,1.0#{0} {1,lower} {2,number}|2.0#{0} {1,upper} {2,number,currency}}"; // Object[] lowArgs = new Object[] {Integer.valueOf(1), "Low", Double.valueOf("1234.56")}; // Object[] highArgs = new Object[] {Integer.valueOf(2), "High", Double.valueOf("9876.54")}; // Locale[] availableLocales = ChoiceFormat.getAvailableLocales(); // Locale[] testLocales = new Locale[availableLocales.length + 1]; // testLocales[0] = null; // System.arraycopy(availableLocales, 0, testLocales, 1, availableLocales.length); // for (int i = 0; i < testLocales.length; i++) { // NumberFormat nf = null; // NumberFormat cf = null; // ExtendedMessageFormat emf = null; // if (testLocales[i] == null) { // nf = NumberFormat.getNumberInstance(); // cf = NumberFormat.getCurrencyInstance(); // emf = new ExtendedMessageFormat(pattern, registry); // } else { // nf = NumberFormat.getNumberInstance(testLocales[i]); // cf = NumberFormat.getCurrencyInstance(testLocales[i]); // emf = new ExtendedMessageFormat(pattern, testLocales[i], registry); // } // assertPatterns(null, pattern, emf.toPattern()); // try { // String lowExpected = lowArgs[0] + " low " + nf.format(lowArgs[2]); // String highExpected = highArgs[0] + " HIGH " + cf.format(highArgs[2]); // assertEquals(lowExpected, emf.format(lowArgs)); // assertEquals(highExpected, emf.format(highArgs)); // } catch (IllegalArgumentException e) { // // currently sub-formats not supported // } // } // } /** * Test a built in format for the specified Locales, plus {@code null} Locale. * * @param pattern MessageFormat pattern * @param fmtRegistry FormatFactory registry to use * @param args MessageFormat arguments * @param locales to test */ private void checkBuiltInFormat(final String pattern, final Map fmtRegistry, final Object[] args, final Locale[] locales) { checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null); for (final Locale locale : locales) { checkBuiltInFormat(pattern, fmtRegistry, args, locale); } } /** * Test a built in format for the specified Locales, plus {@code null} Locale. * * @param pattern MessageFormat pattern * @param args MessageFormat arguments * @param locales to test */ private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) { checkBuiltInFormat(pattern, null, args, locales); } /** * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4). * * @param pattern string * @param locale Locale * @return MessageFormat */ private MessageFormat createMessageFormat(final String pattern, final Locale locale) { final MessageFormat result = new MessageFormat(pattern); if (locale != null) { result.setLocale(locale); result.applyPattern(pattern); } return result; } @BeforeEach public void setUp() { registry.put("lower", LowerCaseFormat.FACTORY); registry.put("upper", UpperCaseFormat.FACTORY); } /** * Test the built in choice format. */ @Test void testBuiltInChoiceFormat() { final Object[] values = new Number[] { 1, Double.valueOf("2.2"), Double.valueOf("1234.5") }; String choicePattern; final Locale[] availableLocales = NumberFormat.getAvailableLocales(); choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}"; for (final Object value : values) { checkBuiltInFormat(value + ": " + choicePattern, new Object[] { value }, availableLocales); } choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}"; for (final Object value : values) { checkBuiltInFormat(value + ": " + choicePattern, new Object[] { value }, availableLocales); } } /** * Test the built in date/time formats */ @Test void testBuiltInDateTimeFormat() { final Calendar cal = Calendar.getInstance(); cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5); final Object[] args = { cal.getTime() }; final Locale[] availableLocales = DateFormat.getAvailableLocales(); checkBuiltInFormat("1: {0,date,short}", args, availableLocales); checkBuiltInFormat("2: {0,date,medium}", args, availableLocales); checkBuiltInFormat("3: {0,date,long}", args, availableLocales); checkBuiltInFormat("4: {0,date,full}", args, availableLocales); checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales); checkBuiltInFormat("6: {0,time,short}", args, availableLocales); checkBuiltInFormat("7: {0,time,medium}", args, availableLocales); checkBuiltInFormat("8: {0,time,long}", args, availableLocales); checkBuiltInFormat("9: {0,time,full}", args, availableLocales); checkBuiltInFormat("10: {0,time,HH:mm}", args, availableLocales); checkBuiltInFormat("11: {0,date}", args, availableLocales); checkBuiltInFormat("12: {0,time}", args, availableLocales); } /** * Test the built in number formats. */ @Test void testBuiltInNumberFormat() { final Object[] args = { Double.valueOf("6543.21") }; final Locale[] availableLocales = NumberFormat.getAvailableLocales(); checkBuiltInFormat("1: {0,number}", args, availableLocales); checkBuiltInFormat("2: {0,number,integer}", args, availableLocales); checkBuiltInFormat("3: {0,number,currency}", args, availableLocales); checkBuiltInFormat("4: {0,number,percent}", args, availableLocales); checkBuiltInFormat("5: {0,number,00000.000}", args, availableLocales); } /** * Test Bug TEXT-106 - Exception while using ExtendedMessageFormat and choice format element with quote just before brace end */ @Test void testChoiceQuoteJustBeforeBraceEnd_TEXT_106() { final String pattern2 = "Choice format element with quote just before brace end ''{0,choice,0#0|0<'1'}''"; final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern2, registry); assertEquals("Choice format element with quote just before brace end '0'", emf.format(new Object[] { 0 })); assertEquals("Choice format element with quote just before brace end '1'", emf.format(new Object[] { 1 })); } @Test void testCreatesExtendedMessageFormatTakingString() { final ExtendedMessageFormat extendedMessageFormat = new ExtendedMessageFormat("Unterminated format element at position "); final Map map = new HashMap<>(); final ExtendedMessageFormat extendedMessageFormatTwo = new ExtendedMessageFormat("Unterminated format element at position ", map); assertEquals("Unterminated format element at position ", extendedMessageFormatTwo.toPattern()); assertNotEquals(extendedMessageFormat, extendedMessageFormatTwo); } /** * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern */ @Test void testEmbeddedPatternInChoice() { final String pattern = "Hi {0,lower}, got {1,choice,0#none|1#one|1<{1,number}}, {2,upper}!"; final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry); assertEquals("Hi there, got 3, GREAT!", emf.format(new Object[] { "there", 3, "great" })); } /** * Test equals() and hashCode(). */ @Test void testEqualsHashcode() { final Map fmtRegistry = Collections.singletonMap("testfmt", LowerCaseFormat.FACTORY); final Map otherRegistry = Collections.singletonMap("testfmt", UpperCaseFormat.FACTORY); final String pattern = "Pattern: {0,testfmt}"; final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry); ExtendedMessageFormat other; // Same object assertEquals(emf, emf, "same, equals()"); assertEquals(emf.hashCode(), emf.hashCode(), "same, hashCode()"); assertNotEquals(null, emf, "null, equals"); // Equal Object other = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry); assertEquals(emf, other, "equal, equals()"); assertEquals(emf.hashCode(), other.hashCode(), "equal, hashCode()"); // Different Class other = new OtherExtendedMessageFormat(pattern, Locale.US, fmtRegistry); assertNotEquals(emf, other, "class, equals()"); assertEquals(emf.hashCode(), other.hashCode(), "class, hashCode()"); // same hash code // Different pattern other = new ExtendedMessageFormat("X" + pattern, Locale.US, fmtRegistry); assertNotEquals(emf, other, "pattern, equals()"); assertNotEquals(emf.hashCode(), other.hashCode(), "pattern, hashCode()"); // Different registry other = new ExtendedMessageFormat(pattern, Locale.US, otherRegistry); assertNotEquals(emf, other, "registry, equals()"); assertNotEquals(emf.hashCode(), other.hashCode(), "registry, hashCode()"); // Different Locale other = new ExtendedMessageFormat(pattern, Locale.FRANCE, fmtRegistry); assertNotEquals(emf, other, "locale, equals()"); assertEquals(emf.hashCode(), other.hashCode(), "locale, hashCode()"); // same hash code } /** * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces */ @Test void testEscapedBraces_LANG_948() { // message without placeholder because braces are escaped by quotes final String pattern = "Message without placeholders '{}'"; final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry); assertEquals("Message without placeholders {}", emf.format(new Object[] { "DUMMY" })); // message with placeholder because quotes are escaped by quotes final String pattern2 = "Message with placeholder ''{0}''"; final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry); assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] { "DUMMY" })); } /** * Test Bug LANG-477 - out of memory error with escaped quote */ @Test void testEscapedQuote_LANG_477() { final String pattern = "it''s a {0,lower} 'test'!"; final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry); assertEquals("it's a dummy test!", emf.format(new Object[] { "DUMMY" })); } /** * Test extended and built in formats. */ @Test void testExtendedAndBuiltInFormats() { final Calendar cal = Calendar.getInstance(); cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5); final Object[] args = { "John Doe", cal.getTime(), Double.valueOf("12345.67") }; final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}"; final String extendedPattern = "Name: {0,upper} "; final String pattern = extendedPattern + builtinsPattern; final HashSet testLocales = new HashSet<>(Arrays.asList(DateFormat.getAvailableLocales())); testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales())); testLocales.add(null); for (final Locale locale : testLocales) { final MessageFormat builtins = createMessageFormat(builtinsPattern, locale); final String expectedPattern = extendedPattern + builtins.toPattern(); DateFormat df = null; NumberFormat nf = null; ExtendedMessageFormat emf = null; if (locale == null) { df = DateFormat.getDateInstance(DateFormat.SHORT); nf = NumberFormat.getCurrencyInstance(); emf = new ExtendedMessageFormat(pattern, registry); } else { df = DateFormat.getDateInstance(DateFormat.SHORT, locale); nf = NumberFormat.getCurrencyInstance(locale); emf = new ExtendedMessageFormat(pattern, locale, registry); } final StringBuilder expected = new StringBuilder(); expected.append("Name: "); expected.append(args[0].toString().toUpperCase(Locale.ROOT)); expected.append(" DOB: "); expected.append(df.format(args[1])); expected.append(" Salary: "); expected.append(nf.format(args[2])); assertEquals(expectedPattern, emf.toPattern(), "pattern comparison for locale " + locale); assertEquals(expected.toString(), emf.format(args), String.valueOf(locale)); } } /** * Test extended formats. */ @Test void testExtendedFormats() { final String pattern = "Lower: {0,lower} Upper: {1,upper}"; final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry); assertEquals(pattern, emf.toPattern(), "TOPATTERN"); assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] { "foo", "bar" })); assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] { "Foo", "Bar" })); assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] { "FOO", "BAR" })); assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] { "FOO", "bar" })); assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] { "foo", "BAR" })); } @Test void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFive() { assertThrowsExactly(IllegalArgumentException.class, () -> new ExtendedMessageFormat("j/[_D9{0,\"&'+0o", new HashMap<>())); } @Test void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFour() { assertThrowsExactly(IllegalArgumentException.class, () -> new ExtendedMessageFormat("RD,nXhM{}{", new HashMap<>())); } @Test void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionOne() { assertThrowsExactly(IllegalArgumentException.class, () -> new ExtendedMessageFormat("agdXdkR;T1{9 ^,LzXf?", new HashMap<>())); } @Test void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionThree() { assertThrowsExactly(IllegalArgumentException.class, () -> new ExtendedMessageFormat("9jLh_D9{ ", new HashMap<>())); } @Test void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionTwo() { assertThrowsExactly(IllegalArgumentException.class, () -> new ExtendedMessageFormat("a5XdkR;T1{9 ,LzXf?", new HashMap<>())); } @Test void testOverriddenBuiltinFormat() { final Calendar cal = Calendar.getInstance(); cal.set(2007, Calendar.JANUARY, 23); final Object[] args = { cal.getTime() }; final Locale[] availableLocales = DateFormat.getAvailableLocales(); final Map dateRegistry = Collections.singletonMap("date", OverrideShortDateFormatFactory.FACTORY); // check the non-overridden builtins: checkBuiltInFormat("1: {0,date}", dateRegistry, args, availableLocales); checkBuiltInFormat("2: {0,date,medium}", dateRegistry, args, availableLocales); checkBuiltInFormat("3: {0,date,long}", dateRegistry, args, availableLocales); checkBuiltInFormat("4: {0,date,full}", dateRegistry, args, availableLocales); checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales); // check the overridden format: for (int i = -1; i < availableLocales.length; i++) { final Locale locale = i < 0 ? null : availableLocales[i]; final MessageFormat dateDefault = createMessageFormat("{0,date}", locale); final String pattern = "{0,date,short}"; final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry); assertEquals(dateDefault.format(args), dateShort.format(args), "overridden date,short format"); assertEquals(pattern, dateShort.toPattern(), "overridden date,short pattern"); } } @Test void testSetFormatByArgumentIndexIsUnsupported() { assertThrowsExactly(UnsupportedOperationException.class, () -> new ExtendedMessageFormat("").setFormatByArgumentIndex(0, new LowerCaseFormat())); } @Test void testSetFormatIsUnsupported() { assertThrowsExactly(UnsupportedOperationException.class, () -> new ExtendedMessageFormat("").setFormat(0, new LowerCaseFormat())); } @Test void testSetFormatsByArgumentIndex() { assertThrowsExactly(UnsupportedOperationException.class, () -> new ExtendedMessageFormat("").setFormatsByArgumentIndex(new Format[] { new LowerCaseFormat(), new UpperCaseFormat() })); } @Test void testSetFormatsIsUnsupported() { assertThrowsExactly(UnsupportedOperationException.class, () -> new ExtendedMessageFormat("").setFormats(new Format[] { new LowerCaseFormat(), new UpperCaseFormat() })); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/FormattableUtilsTest.java000066400000000000000000000226771511432740600336110ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static java.util.FormattableFlags.LEFT_JUSTIFY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import java.util.Formattable; import java.util.Formatter; import org.junit.jupiter.api.Test; /** * Unit tests {@link FormattableUtils}. */ class FormattableUtilsTest { static class SimplestFormattable implements Formattable { private final String text; SimplestFormattable(final String text) { this.text = text; } @Override public void formatTo(final Formatter formatter, final int flags, final int width, final int precision) { formatter.format(text); } } private Formatter createFormatter() { return new Formatter(); } @Test void testAlternatePadCharacter() { final char pad = '_'; assertEquals("foo", FormattableUtils.append("foo", createFormatter(), 0, -1, -1, pad).toString()); assertEquals("fo", FormattableUtils.append("foo", createFormatter(), 0, -1, 2, pad).toString()); assertEquals("_foo", FormattableUtils.append("foo", createFormatter(), 0, 4, -1, pad).toString()); assertEquals("___foo", FormattableUtils.append("foo", createFormatter(), 0, 6, -1, pad).toString()); assertEquals("_fo", FormattableUtils.append("foo", createFormatter(), 0, 3, 2, pad).toString()); assertEquals("___fo", FormattableUtils.append("foo", createFormatter(), 0, 5, 2, pad).toString()); assertEquals("foo_", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, pad).toString()); assertEquals("foo___", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, pad).toString()); assertEquals("fo_", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, pad).toString()); assertEquals("fo___", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, pad).toString()); } @Test void testAlternatePadCharAndEllipsis() { assertEquals("foo", FormattableUtils.append("foo", createFormatter(), 0, -1, -1, '_', "*").toString()); assertEquals("f*", FormattableUtils.append("foo", createFormatter(), 0, -1, 2, '_', "*").toString()); assertEquals("_foo", FormattableUtils.append("foo", createFormatter(), 0, 4, -1, '_', "*").toString()); assertEquals("___foo", FormattableUtils.append("foo", createFormatter(), 0, 6, -1, '_', "*").toString()); assertEquals("_f*", FormattableUtils.append("foo", createFormatter(), 0, 3, 2, '_', "*").toString()); assertEquals("___f*", FormattableUtils.append("foo", createFormatter(), 0, 5, 2, '_', "*").toString()); assertEquals("foo_", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString()); assertEquals("foo___", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString()); assertEquals("f*_", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString()); assertEquals("f*___", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString()); assertEquals("foo", FormattableUtils.append("foo", createFormatter(), 0, -1, -1, '_', "+*").toString()); assertEquals("+*", FormattableUtils.append("foo", createFormatter(), 0, -1, 2, '_', "+*").toString()); assertEquals("_foo", FormattableUtils.append("foo", createFormatter(), 0, 4, -1, '_', "+*").toString()); assertEquals("___foo", FormattableUtils.append("foo", createFormatter(), 0, 6, -1, '_', "+*").toString()); assertEquals("_+*", FormattableUtils.append("foo", createFormatter(), 0, 3, 2, '_', "+*").toString()); assertEquals("___+*", FormattableUtils.append("foo", createFormatter(), 0, 5, 2, '_', "+*").toString()); assertEquals("foo_", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString()); assertEquals("foo___", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString()); assertEquals("+*_", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString()); assertEquals("+*___", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString()); } @Test void testAppendWithNullFormatterAndIntsThrowsNullPointerException() { assertThrowsExactly(NullPointerException.class, () -> FormattableUtils.append("", null, 0, 0, 0, '}')); } @Test void testDefaultAppend() { assertEquals("foo", FormattableUtils.append("foo", createFormatter(), 0, -1, -1).toString()); assertEquals("fo", FormattableUtils.append("foo", createFormatter(), 0, -1, 2).toString()); assertEquals(" foo", FormattableUtils.append("foo", createFormatter(), 0, 4, -1).toString()); assertEquals(" foo", FormattableUtils.append("foo", createFormatter(), 0, 6, -1).toString()); assertEquals(" fo", FormattableUtils.append("foo", createFormatter(), 0, 3, 2).toString()); assertEquals(" fo", FormattableUtils.append("foo", createFormatter(), 0, 5, 2).toString()); assertEquals("foo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1).toString()); assertEquals("foo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1).toString()); assertEquals("fo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2).toString()); assertEquals("fo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2).toString()); } @Test void testEllipsis() { assertEquals("foo", FormattableUtils.append("foo", createFormatter(), 0, -1, -1, "*").toString()); assertEquals("f*", FormattableUtils.append("foo", createFormatter(), 0, -1, 2, "*").toString()); assertEquals(" foo", FormattableUtils.append("foo", createFormatter(), 0, 4, -1, "*").toString()); assertEquals(" foo", FormattableUtils.append("foo", createFormatter(), 0, 6, -1, "*").toString()); assertEquals(" f*", FormattableUtils.append("foo", createFormatter(), 0, 3, 2, "*").toString()); assertEquals(" f*", FormattableUtils.append("foo", createFormatter(), 0, 5, 2, "*").toString()); assertEquals("foo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, "*").toString()); assertEquals("foo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, "*").toString()); assertEquals("f* ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, "*").toString()); assertEquals("f* ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, "*").toString()); assertEquals("foo", FormattableUtils.append("foo", createFormatter(), 0, -1, -1, "+*").toString()); assertEquals("+*", FormattableUtils.append("foo", createFormatter(), 0, -1, 2, "+*").toString()); assertEquals(" foo", FormattableUtils.append("foo", createFormatter(), 0, 4, -1, "+*").toString()); assertEquals(" foo", FormattableUtils.append("foo", createFormatter(), 0, 6, -1, "+*").toString()); assertEquals(" +*", FormattableUtils.append("foo", createFormatter(), 0, 3, 2, "+*").toString()); assertEquals(" +*", FormattableUtils.append("foo", createFormatter(), 0, 5, 2, "+*").toString()); assertEquals("foo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, "+*").toString()); assertEquals("foo ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, "+*").toString()); assertEquals("+* ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, "+*").toString()); assertEquals("+* ", FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, "+*").toString()); } @Test void testIllegalEllipsis() { assertThrowsExactly(IllegalArgumentException.class, () -> FormattableUtils.append("foo", createFormatter(), 0, -1, 1, "xx")); } @Test void testIllegalEllipsisWith7Args() { final String ellipsis = "xxxx"; final int precisionLessThanEllipsisLength = ellipsis.length() - 1; assertThrowsExactly(IllegalArgumentException.class, () -> FormattableUtils.append("foo", createFormatter(), 0, 0, precisionLessThanEllipsisLength, '}', ellipsis)); } @Test void testPublicConstructorExists() { new FormattableUtils(); } @Test void testSimplestFormat() { final Formattable formattable = new SimplestFormattable("foo"); assertEquals("foo", FormattableUtils.toString(formattable)); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/OssFuzzTest.java000066400000000000000000000410421511432740600317360ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class OssFuzzTest { /** * Input is from clusterfuzz-testcase-StringSubstitutorInterpolatorFuzzer-5447769450741760 * * @throws Exception Thrown when the test fails. */ @Disabled("Until Apache Commons Lang 3.18.0") @Test public void test() throws Exception { StringSubstitutor.createInterpolator().replace( "¿ ,${const:ˇda´~e]W]~t$t${.ubase64encoder{con+s{.ubase64encoder{con+s~t....................................ˇˇˇˇˇˇˇˇˇˇ&${localhot:ˇˇˇˇˇˇ4ˇ..................................s${.!.${.. \\E],${conÅEEE]W€EÅE.!${.ubase64encoder{conÅEEE]W€EÅE.!${.ubase64encoder{con+s~t....................................ˇˇˇˇˇˇˇˇˇˇ&${localhot:ˇˇˇˇˇˇ-636ˇ...............................................................t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--......t]V]W€EÅE.!$${.u--}"); } /** * Input is from clusterfuzz-testcase-StringSubstitutorInterpolatorFuzzer-5447769450741760 * * @throws Exception Thrown when the test fails. */ @Test public void testStringSubstitutorInterpolatorFuzzer5447769450741760() throws Exception { StringSubstitutor.createInterpolator().replace("${date:swswswswswsswswswswswswwswsswswswswsswswswswsswswswswswswswswswswsws}"); } } RandomStringGeneratorTest.java000066400000000000000000000353441511432740600345220ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.util.Arrays; import java.util.function.IntUnaryOperator; import org.apache.commons.lang3.ArraySorter; import org.apache.commons.text.RandomStringGenerator.Builder; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; /** * Tests for {@link RandomStringGenerator}. */ class RandomStringGeneratorTest { private static final CharacterPredicate A_FILTER = codePoint -> codePoint == 'a'; private static final CharacterPredicate B_FILTER = codePoint -> codePoint == 'b'; private static int codePointLength(final String s) { return s.codePointCount(0, s.length()); } @Test void testBadMaximumCodePoint() { assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().withinRange(0, Character.MAX_CODE_POINT + 1)); } @Test void testBadMinAndMax() { assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().withinRange(2, 1)); } @Test void testBadMinimumCodePoint() { assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().withinRange(-1, 1)); } @Test void testBuildDeprecated() { final RandomStringGenerator.Builder builder = RandomStringGenerator.builder().withinRange('a', 'z').filteredBy(A_FILTER); final String str = builder.filteredBy(B_FILTER).build().generate(100); for (final char c : str.toCharArray()) { assertEquals('b', c); } } @Test void testChangeOfFilter() { final RandomStringGenerator.Builder builder = RandomStringGenerator.builder().withinRange('a', 'z').filteredBy(A_FILTER); final String str = builder.filteredBy(B_FILTER).get().generate(100); for (final char c : str.toCharArray()) { assertEquals('b', c); } } @Test void testGenerateMinMaxLength() { final int minLength = 0; final int maxLength = 3; final RandomStringGenerator generator = RandomStringGenerator.builder().get(); final String str = generator.generate(minLength, maxLength); final int codePointLength = codePointLength(str); assertTrue(codePointLength >= minLength && codePointLength <= maxLength); } @Test void testGenerateMinMaxLengthInvalidLength() { assertThrowsExactly(IllegalArgumentException.class, () -> { final RandomStringGenerator generator = RandomStringGenerator.builder().get(); generator.generate(-1, 0); }); } @Test void testGenerateMinMaxLengthMinGreaterThanMax() { assertThrowsExactly(IllegalArgumentException.class, () -> { final RandomStringGenerator generator = RandomStringGenerator.builder().get(); generator.generate(1, 0); }); } @Test void testGenerateTakingIntThrowsNullPointerException() { assertThrowsExactly(NullPointerException.class, () -> { final RandomStringGenerator.Builder randomStringGeneratorBuilder = RandomStringGenerator.builder(); final CharacterPredicate[] characterPredicateArray = new CharacterPredicate[2]; randomStringGeneratorBuilder.filteredBy(characterPredicateArray); final RandomStringGenerator randomStringGenerator = randomStringGeneratorBuilder.get(); randomStringGenerator.generate(18); }); } @Test void testInvalidLength() { assertThrowsExactly(IllegalArgumentException.class, () -> RandomStringGenerator.builder().get().generate(-1)); } @Test void testMultipleFilters() { final String str = RandomStringGenerator.builder().withinRange('a', 'd').filteredBy(A_FILTER, B_FILTER).get().generate(5000); boolean aFound = false; boolean bFound = false; for (final char c : str.toCharArray()) { if (c == 'a') { aFound = true; } else if (c == 'b') { bFound = true; } else { fail("Invalid character"); } } assertTrue(aFound && bFound); } @Test void testNoLoneSurrogates() { final int length = 5000; final String str = RandomStringGenerator.builder().get().generate(length); char lastChar = str.charAt(0); for (int i = 1; i < str.length(); i++) { final char c = str.charAt(i); if (Character.isLowSurrogate(c)) { assertTrue(Character.isHighSurrogate(lastChar)); } if (Character.isHighSurrogate(lastChar)) { assertTrue(Character.isLowSurrogate(c)); } if (Character.isHighSurrogate(c)) { // test this isn't the last character in the string assertTrue(i + 1 < str.length()); } lastChar = c; } } @Test void testNoPrivateCharacters() { final int startOfPrivateBMPChars = 0xE000; // Request a string in an area of the Basic Multilingual Plane that is // largely occupied by private characters final String str = RandomStringGenerator.builder().withinRange(startOfPrivateBMPChars, Character.MIN_SUPPLEMENTARY_CODE_POINT - 1).get() .generate(5000); int i = 0; do { final int codePoint = str.codePointAt(i); assertFalse(Character.getType(codePoint) == Character.PRIVATE_USE); i += Character.charCount(codePoint); } while (i < str.length()); } @Test void testPasswordExample() { final char[] punctuation = ArraySorter .sort(new char[] { '!', '"', '#', '$', '&', '\'', '(', ')', ',', '.', ':', ';', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~' }); // @formatter:off final RandomStringGenerator generator = RandomStringGenerator.builder() .setAccumulate(true) .withinRange('a', 'z') .withinRange('A', 'Z') .withinRange('0', '9') .selectFrom(punctuation) .get(); // @formatter:on final String randomText = generator.generate(10); for (final char c : randomText.toCharArray()) { assertTrue(Character.isLetter(c) || Character.isDigit(c) || Arrays.binarySearch(punctuation, c) >= 0); } } @Test void testRemoveFilters() { final RandomStringGenerator.Builder builder = RandomStringGenerator.builder().withinRange('a', 'z').filteredBy(A_FILTER); builder.filteredBy(); final String str = builder.get().generate(100); for (final char c : str.toCharArray()) { if (c != 'a') { // filter was successfully removed return; } } fail("Filter appears to have remained in place"); } @Test void testSelectFromCharArray() { final String str = "abc"; final char[] charArray = str.toCharArray(); final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom(charArray).get(); final String randomText = generator.generate(5); for (final char c : randomText.toCharArray()) { assertTrue(str.indexOf(c) != -1); } } @Test void testSelectFromCharVarargs() { final String str = "abc"; final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom('a', 'b', 'c').get(); final String randomText = generator.generate(5); for (final char c : randomText.toCharArray()) { assertTrue(str.indexOf(c) != -1); } } @ParameterizedTest @ValueSource(booleans = {false, true}) void testSelectFromCharVarargs2(final boolean accumulate) { final String str = "abcde"; // @formatter:off final RandomStringGenerator generator = RandomStringGenerator.builder() .setAccumulate(accumulate) .selectFrom() .selectFrom(null) .selectFrom('a', 'b') .selectFrom('a', 'b', 'c') .selectFrom('a', 'b', 'c', 'd') .selectFrom('a', 'b', 'c', 'd', 'e') // only this last call matters when accumulate is false .get(); // @formatter:on final String randomText = generator.generate(10); for (final char c : randomText.toCharArray()) { assertTrue(str.indexOf(c) != -1); } } @ParameterizedTest @ValueSource(booleans = {false, true}) void testSelectFromCharVarargs3(final boolean accumulate) { final String str = "abcde"; // @formatter:off final RandomStringGenerator generator = RandomStringGenerator.builder() .setAccumulate(accumulate) .selectFrom('a', 'b', 'c', 'd', 'e') .selectFrom('a', 'b', 'c', 'd') .selectFrom('a', 'b', 'c') .selectFrom('a', 'b') .selectFrom(null) .selectFrom() .get(); // @formatter:on final String randomText = generator.generate(10); for (final char c : randomText.toCharArray()) { assertEquals(accumulate, str.indexOf(c) != -1); } } @Test void testSelectFromCharVarargSize1() { final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom('a').get(); final String randomText = generator.generate(5); for (final char c : randomText.toCharArray()) { assertEquals('a', c); } } @Test void testSelectFromEmptyCharVarargs() { final RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom().get(); final String randomText = generator.generate(5); for (final char c : randomText.toCharArray()) { assertTrue(c >= Character.MIN_CODE_POINT && c <= Character.MAX_CODE_POINT); } } @Test void testSelectFromNullCharVarargs() { final int length = 5; RandomStringGenerator generator = RandomStringGenerator.builder().selectFrom(null).get(); String randomText = generator.generate(length); assertEquals(length, codePointLength(randomText)); for (final char c : randomText.toCharArray()) { assertTrue(c >= Character.MIN_CODE_POINT && c <= Character.MAX_CODE_POINT); } // final Builder builder = RandomStringGenerator.builder().selectFrom('a'); generator = builder.get(); randomText = generator.generate(length); for (final char c : randomText.toCharArray()) { assertEquals('a', c); } // null input resets generator = builder.selectFrom(null).get(); randomText = generator.generate(length); assertEquals(length, codePointLength(randomText)); for (final char c : randomText.toCharArray()) { assertTrue(c >= Character.MIN_CODE_POINT && c <= Character.MAX_CODE_POINT); } } @Test void testSetLength() { final int length = 99; final RandomStringGenerator generator = RandomStringGenerator.builder().get(); final String str = generator.generate(length); assertEquals(length, codePointLength(str)); } @Test void testUsingRandomIntUnaryOperator() { final char testChar = 'a'; final IntUnaryOperator testRandom = n -> testChar; final String str = RandomStringGenerator.builder().usingRandom(testRandom).get().generate(10); for (final char c : str.toCharArray()) { assertEquals(testChar, c); } } @Test void testUsingRandomTextRandomProvider() { final char testChar = 'a'; final TextRandomProvider testRandom = n -> testChar; final String str = RandomStringGenerator.builder().usingRandom(testRandom).get().generate(10); for (final char c : str.toCharArray()) { assertEquals(testChar, c); } } @Test void testWithinMultipleRanges() { final int length = 5000; final char[][] pairs = { { 'a', 'z' }, { '0', '9' } }; // @formatter:off final RandomStringGenerator generator = RandomStringGenerator.builder() .withinRange() .withinRange((char[][]) null) .withinRange(pairs) .get(); // @formatter:on final String str = generator.generate(length); int minimumCodePoint = 0, maximumCodePoint = 0; for (final char[] pair : pairs) { minimumCodePoint = Math.min(minimumCodePoint, pair[0]); maximumCodePoint = Math.max(maximumCodePoint, pair[1]); } int i = 0; do { final int codePoint = str.codePointAt(i); assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint); i += Character.charCount(codePoint); } while (i < str.length()); } @Test void testWithinRange() { final int length = 5000; final int minimumCodePoint = 'a'; final int maximumCodePoint = 'z'; final RandomStringGenerator generator = RandomStringGenerator.builder().withinRange(minimumCodePoint, maximumCodePoint).get(); final String str = generator.generate(length); int i = 0; do { final int codePoint = str.codePointAt(i); assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint); i += Character.charCount(codePoint); } while (i < str.length()); } @Test void testZeroLength() { final RandomStringGenerator generator = RandomStringGenerator.builder().get(); assertEquals("", generator.generate(0)); } } StrBuilderAppendInsertTest.java000066400000000000000000001302151511432740600346310ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import java.text.DecimalFormatSymbols; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.Test; /** * Tests {@link StrBuilder}. * * @deprecated This class will be removed in 2.0. */ @Deprecated class StrBuilderAppendInsertTest { /** The system line separator. */ private static final String SEP = System.lineSeparator(); /** Test subclass of Object, with a toString method. */ private static final Object FOO = new Object() { @Override public String toString() { return "foo"; } }; @Test void testAppend_Boolean() { final StrBuilder sb = new StrBuilder(); sb.append(true); assertEquals("true", sb.toString()); sb.append(false); assertEquals("truefalse", sb.toString()); sb.append('!'); assertEquals("truefalse!", sb.toString()); } @Test void testAppend_CharArray() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((char[]) null); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(ArrayUtils.EMPTY_CHAR_ARRAY); assertEquals("", sb.toString()); sb.append(new char[] { 'f', 'o', 'o' }); assertEquals("foo", sb.toString()); } @Test void testAppend_CharArray_int_int() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((char[]) null, 0, 1); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new char[] { 'f', 'o', 'o' }, 0, 3); assertEquals("foo", sb.toString()); try { sb.append(new char[] { 'b', 'a', 'r' }, -1, 1); fail("append(char[], -1,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new char[] { 'b', 'a', 'r' }, 3, 1); fail("append(char[], 3,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new char[] { 'b', 'a', 'r' }, 1, -1); fail("append(char[],, -1) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new char[] { 'b', 'a', 'r' }, 1, 3); fail("append(char[], 1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new char[] { 'b', 'a', 'r' }, -1, 3); fail("append(char[], -1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new char[] { 'b', 'a', 'r' }, 4, 0); fail("append(char[], 4, 0) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } sb.append(new char[] { 'b', 'a', 'r' }, 3, 0); assertEquals("foo", sb.toString()); sb.append(new char[] { 'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f' }, 3, 3); assertEquals("foobar", sb.toString()); } @Test void testAppend_FormattedString() { StrBuilder sb; sb = new StrBuilder(); sb.append("Hi", (Object[]) null); assertEquals("Hi", sb.toString()); sb = new StrBuilder(); sb.append("Hi", "Alice"); assertEquals("Hi", sb.toString()); sb = new StrBuilder(); sb.append("Hi %s", "Alice"); assertEquals("Hi Alice", sb.toString()); sb = new StrBuilder(); sb.append("Hi %s %,d", "Alice", 5000); // group separator depends on system locale final char groupingSeparator = DecimalFormatSymbols.getInstance().getGroupingSeparator(); final String expected = "Hi Alice 5" + groupingSeparator + "000"; assertEquals(expected, sb.toString()); } @Test void testAppend_Object() { final StrBuilder sb = new StrBuilder(); sb.appendNull(); assertEquals("", sb.toString()); sb.append((Object) null); assertEquals("", sb.toString()); sb.append(FOO); assertEquals("foo", sb.toString()); sb.append((StringBuffer) null); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("baz")); assertEquals("foobaz", sb.toString()); sb.append(new StrBuilder("yes")); assertEquals("foobazyes", sb.toString()); sb.append((CharSequence) "Seq"); assertEquals("foobazyesSeq", sb.toString()); sb.append(new StringBuilder("bld")); // Check it supports StringBuilder assertEquals("foobazyesSeqbld", sb.toString()); } @Test void testAppend_PrimitiveNumber() { final StrBuilder sb = new StrBuilder(); sb.append(0); assertEquals("0", sb.toString()); sb.append(1L); assertEquals("01", sb.toString()); sb.append(2.3f); assertEquals("012.3", sb.toString()); sb.append(4.5d); assertEquals("012.34.5", sb.toString()); } @Test void testAppend_StrBuilder() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((StrBuilder) null); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new StrBuilder("foo")); assertEquals("foo", sb.toString()); sb.append(new StrBuilder("")); assertEquals("foo", sb.toString()); sb.append(new StrBuilder("bar")); assertEquals("foobar", sb.toString()); } @Test void testAppend_StrBuilder_int_int() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((StrBuilder) null, 0, 1); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new StrBuilder("foo"), 0, 3); assertEquals("foo", sb.toString()); try { sb.append(new StrBuilder("bar"), -1, 1); fail("append(char[], -1,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StrBuilder("bar"), 3, 1); fail("append(char[], 3,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StrBuilder("bar"), 1, -1); fail("append(char[],, -1) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StrBuilder("bar"), 1, 3); fail("append(char[], 1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StrBuilder("bar"), -1, 3); fail("append(char[], -1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StrBuilder("bar"), 4, 0); fail("append(char[], 4, 0) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } sb.append(new StrBuilder("bar"), 3, 0); assertEquals("foo", sb.toString()); sb.append(new StrBuilder("abcbardef"), 3, 3); assertEquals("foobar", sb.toString()); } @Test void testAppend_String() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((String) null); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append("foo"); assertEquals("foo", sb.toString()); sb.append(""); assertEquals("foo", sb.toString()); sb.append("bar"); assertEquals("foobar", sb.toString()); } @Test void testAppend_String_int_int() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((String) null, 0, 1); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append("foo", 0, 3); assertEquals("foo", sb.toString()); try { sb.append("bar", -1, 1); fail("append(char[], -1,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append("bar", 3, 1); fail("append(char[], 3,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append("bar", 1, -1); fail("append(char[],, -1) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append("bar", 1, 3); fail("append(char[], 1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append("bar", -1, 3); fail("append(char[], -1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append("bar", 4, 0); fail("append(char[], 4, 0) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } sb.append("bar", 3, 0); assertEquals("foo", sb.toString()); sb.append("abcbardef", 3, 3); assertEquals("foobar", sb.toString()); sb.append((CharSequence) "abcbardef", 4, 3); assertEquals("foobarard", sb.toString()); } @Test void testAppend_StringBuffer() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((StringBuffer) null); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new StringBuffer("foo")); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("")); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("bar")); assertEquals("foobar", sb.toString()); } @Test void testAppend_StringBuffer_int_int() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((StringBuffer) null, 0, 1); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new StringBuffer("foo"), 0, 3); assertEquals("foo", sb.toString()); try { sb.append(new StringBuffer("bar"), -1, 1); fail("append(char[], -1,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuffer("bar"), 3, 1); fail("append(char[], 3,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuffer("bar"), 1, -1); fail("append(char[],, -1) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuffer("bar"), 1, 3); fail("append(char[], 1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuffer("bar"), -1, 3); fail("append(char[], -1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuffer("bar"), 4, 0); fail("append(char[], 4, 0) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } sb.append(new StringBuffer("bar"), 3, 0); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("abcbardef"), 3, 3); assertEquals("foobar", sb.toString()); } @Test void testAppend_StringBuilder() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((String) null); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new StringBuilder("foo")); assertEquals("foo", sb.toString()); sb.append(new StringBuilder("")); assertEquals("foo", sb.toString()); sb.append(new StringBuilder("bar")); assertEquals("foobar", sb.toString()); } @Test void testAppend_StringBuilder_int_int() { StrBuilder sb = new StrBuilder(); sb.setNullText("NULL").append((String) null, 0, 1); assertEquals("NULL", sb.toString()); sb = new StrBuilder(); sb.append(new StringBuilder("foo"), 0, 3); assertEquals("foo", sb.toString()); try { sb.append(new StringBuilder("bar"), -1, 1); fail("append(StringBuilder, -1,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuilder("bar"), 3, 1); fail("append(StringBuilder, 3,) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuilder("bar"), 1, -1); fail("append(StringBuilder,, -1) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuilder("bar"), 1, 3); fail("append(StringBuilder, 1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuilder("bar"), -1, 3); fail("append(StringBuilder, -1, 3) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.append(new StringBuilder("bar"), 4, 0); fail("append(StringBuilder, 4, 0) expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } sb.append(new StringBuilder("bar"), 3, 0); assertEquals("foo", sb.toString()); sb.append(new StringBuilder("abcbardef"), 3, 3); assertEquals("foobar", sb.toString()); sb.append(new StringBuilder("abcbardef"), 4, 3); assertEquals("foobarard", sb.toString()); } @Test void testAppendAll_Array() { final StrBuilder sb = new StrBuilder(); sb.appendAll((Object[]) null); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(); assertEquals("", sb.toString()); sb.clear(); sb.appendAll("foo", "bar", "baz"); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendAll("foo", "bar", "baz"); assertEquals("foobarbaz", sb.toString()); } @Test void testAppendAll_Collection() { final StrBuilder sb = new StrBuilder(); sb.appendAll((Collection) null); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Collections.EMPTY_LIST); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Arrays.asList("foo", "bar", "baz")); assertEquals("foobarbaz", sb.toString()); } @Test void testAppendAll_Iterator() { final StrBuilder sb = new StrBuilder(); sb.appendAll((Iterator) null); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Collections.EMPTY_LIST.iterator()); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Arrays.asList("foo", "bar", "baz").iterator()); assertEquals("foobarbaz", sb.toString()); } @Test void testAppendFixedWidthPadLeft() { final StrBuilder sb = new StrBuilder(); sb.appendFixedWidthPadLeft("foo", -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 1, '-'); assertEquals("o", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 2, '-'); assertEquals("oo", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 3, '-'); assertEquals("foo", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 4, '-'); assertEquals("-foo", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("-------foo", sb.toString()); sb.clear(); sb.setNullText("null"); sb.appendFixedWidthPadLeft(null, 5, '-'); assertEquals("-null", sb.toString()); } @Test void testAppendFixedWidthPadLeft_int() { final StrBuilder sb = new StrBuilder(); sb.appendFixedWidthPadLeft(123, -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 1, '-'); assertEquals("3", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 2, '-'); assertEquals("23", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 3, '-'); assertEquals("123", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 4, '-'); assertEquals("-123", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("-------123", sb.toString()); } @Test void testAppendFixedWidthPadRight() { final StrBuilder sb = new StrBuilder(); sb.appendFixedWidthPadRight("foo", -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 1, '-'); assertEquals("f", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 2, '-'); assertEquals("fo", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 3, '-'); assertEquals("foo", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 4, '-'); assertEquals("foo-", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("foo-------", sb.toString()); sb.clear(); sb.setNullText("null"); sb.appendFixedWidthPadRight(null, 5, '-'); assertEquals("null-", sb.toString()); } @Test void testAppendFixedWidthPadRight_int() { final StrBuilder sb = new StrBuilder(); sb.appendFixedWidthPadRight(123, -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 1, '-'); assertEquals("1", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 2, '-'); assertEquals("12", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 3, '-'); assertEquals("123", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 4, '-'); assertEquals("123-", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("123-------", sb.toString()); } @Test void testAppendln_Boolean() { final StrBuilder sb = new StrBuilder(); sb.appendln(true); assertEquals("true" + SEP, sb.toString()); sb.clear(); sb.appendln(false); assertEquals("false" + SEP, sb.toString()); } @Test void testAppendln_CharArray() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final char[] str) { count[0]++; return super.append(str); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln("foo".toCharArray()); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_CharArray_int_int() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final char[] str, final int startIndex, final int length) { count[0]++; return super.append(str, startIndex, length); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln("foo".toCharArray(), 0, 3); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_FormattedString() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final String str) { count[0]++; return super.append(str); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln("Hello %s", "Alice"); assertEquals("Hello Alice" + SEP, sb.toString()); assertEquals(2, count[0]); // appendNewLine() calls append(String) assertEquals(1, count[1]); } @Test void testAppendln_Object() { final StrBuilder sb = new StrBuilder(); sb.appendln((Object) null); assertEquals("" + SEP, sb.toString()); sb.appendln(FOO); assertEquals(SEP + "foo" + SEP, sb.toString()); sb.appendln(Integer.valueOf(6)); assertEquals(SEP + "foo" + SEP + "6" + SEP, sb.toString()); } @Test void testAppendln_PrimitiveNumber() { final StrBuilder sb = new StrBuilder(); sb.appendln(0); assertEquals("0" + SEP, sb.toString()); sb.clear(); sb.appendln(1L); assertEquals("1" + SEP, sb.toString()); sb.clear(); sb.appendln(2.3f); assertEquals("2.3" + SEP, sb.toString()); sb.clear(); sb.appendln(4.5d); assertEquals("4.5" + SEP, sb.toString()); } @Test void testAppendln_StrBuilder() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final StrBuilder str) { count[0]++; return super.append(str); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln(new StrBuilder("foo")); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_StrBuilder_int_int() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final StrBuilder str, final int startIndex, final int length) { count[0]++; return super.append(str, startIndex, length); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln(new StrBuilder("foo"), 0, 3); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_String() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final String str) { count[0]++; return super.append(str); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln("foo"); assertEquals("foo" + SEP, sb.toString()); assertEquals(2, count[0]); // appendNewLine() calls append(String) assertEquals(1, count[1]); } @Test void testAppendln_String_int_int() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final String str, final int startIndex, final int length) { count[0]++; return super.append(str, startIndex, length); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln("foo", 0, 3); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_StringBuffer() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final StringBuffer str) { count[0]++; return super.append(str); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln(new StringBuffer("foo")); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_StringBuffer_int_int() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final StringBuffer str, final int startIndex, final int length) { count[0]++; return super.append(str, startIndex, length); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln(new StringBuffer("foo"), 0, 3); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_StringBuilder() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final StringBuilder str) { count[0]++; return super.append(str); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln(new StringBuilder("foo")); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendln_StringBuilder_int_int() { final int[] count = new int[2]; final StrBuilder sb = new StrBuilder() { private static final long serialVersionUID = 1L; @Override public StrBuilder append(final StringBuilder str, final int startIndex, final int length) { count[0]++; return super.append(str, startIndex, length); } @Override public StrBuilder appendNewLine() { count[1]++; return super.appendNewLine(); } }; sb.appendln(new StringBuilder("foo"), 0, 3); assertEquals("foo" + SEP, sb.toString()); assertEquals(1, count[0]); assertEquals(1, count[1]); } @Test void testAppendNewLine() { StrBuilder sb = new StrBuilder("---"); sb.appendNewLine().append("+++"); assertEquals("---" + SEP + "+++", sb.toString()); sb = new StrBuilder("---"); sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine(); assertEquals("---#" + SEP, sb.toString()); } @Test void testAppendPadding() { final StrBuilder sb = new StrBuilder(); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendPadding(-1, '-'); assertEquals("foo", sb.toString()); sb.appendPadding(0, '-'); assertEquals("foo", sb.toString()); sb.appendPadding(1, '-'); assertEquals("foo-", sb.toString()); sb.appendPadding(16, '-'); assertEquals(20, sb.length()); // 12345678901234567890 assertEquals("foo-----------------", sb.toString()); } @Test void testAppendSeparator_char() { final StrBuilder sb = new StrBuilder(); sb.appendSeparator(','); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(','); assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_char_char() { final StrBuilder sb = new StrBuilder(); final char startSeparator = ':'; final char standardSeparator = ','; final String foo = "foo"; sb.appendSeparator(standardSeparator, startSeparator); // no effect assertEquals(String.valueOf(startSeparator), sb.toString()); sb.append(foo); assertEquals(String.valueOf(startSeparator) + foo, sb.toString()); sb.appendSeparator(standardSeparator, startSeparator); assertEquals(String.valueOf(startSeparator) + foo + standardSeparator, sb.toString()); } @Test void testAppendSeparator_char_int() { final StrBuilder sb = new StrBuilder(); sb.appendSeparator(',', 0); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(',', 1); assertEquals("foo,", sb.toString()); sb.appendSeparator(',', -1); // no effect assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_String() { final StrBuilder sb = new StrBuilder(); sb.appendSeparator(","); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(","); assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_String_int() { final StrBuilder sb = new StrBuilder(); sb.appendSeparator(",", 0); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(",", 1); assertEquals("foo,", sb.toString()); sb.appendSeparator(",", -1); // no effect assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_String_String() { final StrBuilder sb = new StrBuilder(); final String startSeparator = "order by "; final String standardSeparator = ","; final String foo = "foo"; sb.appendSeparator(null, null); assertEquals("", sb.toString()); sb.appendSeparator(standardSeparator, null); assertEquals("", sb.toString()); sb.appendSeparator(standardSeparator, startSeparator); assertEquals(startSeparator, sb.toString()); sb.appendSeparator(null, null); assertEquals(startSeparator, sb.toString()); sb.appendSeparator(null, startSeparator); assertEquals(startSeparator, sb.toString()); sb.append(foo); assertEquals(startSeparator + foo, sb.toString()); sb.appendSeparator(standardSeparator, startSeparator); assertEquals(startSeparator + foo + standardSeparator, sb.toString()); } @Test void testAppendWithNullText() { final StrBuilder sb = new StrBuilder(); sb.setNullText("NULL"); assertEquals("", sb.toString()); sb.appendNull(); assertEquals("NULL", sb.toString()); sb.append((Object) null); assertEquals("NULLNULL", sb.toString()); sb.append(FOO); assertEquals("NULLNULLfoo", sb.toString()); sb.append((String) null); assertEquals("NULLNULLfooNULL", sb.toString()); sb.append(""); assertEquals("NULLNULLfooNULL", sb.toString()); sb.append("bar"); assertEquals("NULLNULLfooNULLbar", sb.toString()); sb.append((StringBuffer) null); assertEquals("NULLNULLfooNULLbarNULL", sb.toString()); sb.append(new StringBuffer("baz")); assertEquals("NULLNULLfooNULLbarNULLbaz", sb.toString()); } @Test void testAppendWithSeparators_Array() { final StrBuilder sb = new StrBuilder(); sb.appendWithSeparators((Object[]) null, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(ArrayUtils.EMPTY_OBJECT_ARRAY, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(new Object[] { "foo", "bar", "baz" }, ","); assertEquals("foo,bar,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(new Object[] { "foo", "bar", "baz" }, null); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendWithSeparators(new Object[] { "foo", null, "baz" }, ","); assertEquals("foo,,baz", sb.toString()); } @Test void testAppendWithSeparators_Collection() { final StrBuilder sb = new StrBuilder(); sb.appendWithSeparators((Collection) null, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Collections.EMPTY_LIST, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz"), ","); assertEquals("foo,bar,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz"), null); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", null, "baz"), ","); assertEquals("foo,,baz", sb.toString()); } @Test void testAppendWithSeparators_Iterator() { final StrBuilder sb = new StrBuilder(); sb.appendWithSeparators((Iterator) null, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Collections.EMPTY_LIST.iterator(), ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz").iterator(), ","); assertEquals("foo,bar,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz").iterator(), null); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", null, "baz").iterator(), ","); assertEquals("foo,,baz", sb.toString()); } @Test void testAppendWithSeparatorsWithNullText() { final StrBuilder sb = new StrBuilder(); sb.setNullText("null"); sb.appendWithSeparators(new Object[] { "foo", null, "baz" }, ","); assertEquals("foo,null,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", null, "baz"), ","); assertEquals("foo,null,baz", sb.toString()); } @Test void testInsert() { final StrBuilder sb = new StrBuilder(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, FOO)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, FOO)); sb.insert(0, (Object) null); assertEquals("barbaz", sb.toString()); sb.insert(0, FOO); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, "foo")); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, "foo")); sb.insert(0, (String) null); assertEquals("barbaz", sb.toString()); sb.insert(0, "foo"); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, new char[] { 'f', 'o', 'o' })); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, new char[] { 'f', 'o', 'o' })); sb.insert(0, (char[]) null); assertEquals("barbaz", sb.toString()); sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY); assertEquals("barbaz", sb.toString()); sb.insert(0, new char[] { 'f', 'o', 'o' }); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 3, 3)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 3, 3)); sb.insert(0, (char[]) null, 0, 0); assertEquals("barbaz", sb.toString()); sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY, 0, 0); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, -1, 3)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 10, 3)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 0, -1)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 0, 10)); sb.insert(0, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 0, 0); assertEquals("barbaz", sb.toString()); sb.insert(0, new char[] { 'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f' }, 3, 3); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, true)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, true)); sb.insert(0, true); assertEquals("truebarbaz", sb.toString()); sb.insert(0, false); assertEquals("falsetruebarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, '!')); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, '!')); sb.insert(0, '!'); assertEquals("!barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 0)); sb.insert(0, '0'); assertEquals("0barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 1L)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 1L)); sb.insert(0, 1L); assertEquals("1barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 2.3F)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 2.3F)); sb.insert(0, 2.3F); assertEquals("2.3barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 4.5D)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 4.5D)); sb.insert(0, 4.5D); assertEquals("4.5barbaz", sb.toString()); } @Test void testInsertWithNullText() { final StrBuilder sb = new StrBuilder(); sb.setNullText("null"); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, FOO)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, FOO)); sb.insert(0, (Object) null); assertEquals("nullbarbaz", sb.toString()); sb.insert(0, FOO); assertEquals("foonullbarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, "foo")); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, "foo")); sb.insert(0, (String) null); assertEquals("nullbarbaz", sb.toString()); sb.insert(0, "foo"); assertEquals("foonullbarbaz", sb.toString()); sb.insert(0, (char[]) null); assertEquals("nullfoonullbarbaz", sb.toString()); sb.insert(0, (char[]) null, 0, 0); assertEquals("nullnullfoonullbarbaz", sb.toString()); } /** See: https://issues.apache.org/jira/browse/LANG-299 */ @Test void testLang299() { final StrBuilder sb = new StrBuilder(1); sb.appendFixedWidthPadRight("foo", 1, '-'); assertEquals("f", sb.toString()); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/StrBuilderTest.java000066400000000000000000002103021511432740600323670ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import org.junit.jupiter.api.Test; /** * Tests {@link StrBuilder}. * * @deprecated This class will be removed in 2.0. */ @Deprecated class StrBuilderTest { private static final class MockReadable implements Readable { private final CharBuffer src; MockReadable(final String src) { this.src = CharBuffer.wrap(src); } @Override public int read(final CharBuffer cb) throws IOException { return src.read(cb); } } static final StrMatcher A_NUMBER_MATCHER = new StrMatcher() { @Override public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) { if (buffer[pos] == 'A') { pos++; if (pos < bufferEnd && buffer[pos] >= '0' && buffer[pos] <= '9') { return 2; } } return 0; } }; @Test void test_LANG_1131_EqualsWithNullStrBuilder() throws Exception { final StrBuilder sb = new StrBuilder(); final StrBuilder other = null; assertFalse(sb.equals(other)); } @Test void testAppendCharBuffer() { final StrBuilder sb1 = new StrBuilder(); final CharBuffer buf = CharBuffer.allocate(10); buf.append("0123456789"); buf.flip(); sb1.append(buf); assertEquals("0123456789", sb1.toString()); final StrBuilder sb2 = new StrBuilder(); sb2.append(buf, 1, 8); assertEquals("12345678", sb2.toString()); } @Test void testAppendCharBufferException() throws Exception { final StrBuilder sb = new StrBuilder("1234567890"); final String text = "Test"; final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length()); buffer.put(text); buffer.flip(); try { sb.append(buffer, -1, 12); } catch (final StringIndexOutOfBoundsException e) { assertEquals("startIndex must be valid", e.getMessage()); } try { sb.append(buffer, 0, -1); } catch (final StringIndexOutOfBoundsException e) { assertEquals("length must be valid", e.getMessage()); } sb.append(buffer); assertEquals("1234567890Test", sb.toString()); } @Test void testAppendCharBufferNull() throws Exception { final StrBuilder sb = new StrBuilder("1234567890"); final CharBuffer buffer = null; sb.append(buffer); assertEquals("1234567890", sb.toString()); final StrBuilder sb1 = new StrBuilder("1234567890"); final CharBuffer buffer1 = null; sb.append(buffer1, 0, 0); assertEquals("1234567890", sb1.toString()); } @Test void testAppendCharSequence() { final CharSequence obj0 = null; final CharSequence obj1 = new StrBuilder("test1"); final CharSequence obj2 = new StringBuilder("test2"); final CharSequence obj3 = new StringBuffer("test3"); final CharBuffer obj4 = CharBuffer.wrap("test4".toCharArray()); final StrBuilder sb0 = new StrBuilder(); assertEquals("", sb0.append(obj0).toString()); final StrBuilder sb1 = new StrBuilder(); assertEquals("test1", sb1.append(obj1).toString()); final StrBuilder sb2 = new StrBuilder(); assertEquals("test2", sb2.append(obj2).toString()); final StrBuilder sb3 = new StrBuilder(); assertEquals("test3", sb3.append(obj3).toString()); final StrBuilder sb4 = new StrBuilder(); assertEquals("test4", sb4.append(obj4).toString()); final StrBuilder sb5 = new StrBuilder(); assertEquals("", sb5.append(obj0, 0, 0).toString()); } @Test void testAppendln() { final StrBuilder sb1 = new StrBuilder(); final char ch = 'c'; assertEquals("c" + System.lineSeparator(), sb1.appendln(ch).toString()); } @Test void testAppendStringBuilderNull() { final StrBuilder sb1 = new StrBuilder(); final StringBuilder b = null; assertEquals("", sb1.append(b).toString()); final StrBuilder sb2 = new StrBuilder(); assertEquals("", sb2.append(b, 0, 0).toString()); } @Test void testAppendTakingTwoIntsWithIndexOutOfBoundsThrowsStringIndexOutOfBoundsExceptionTwo() { assertThrows(StringIndexOutOfBoundsException.class, () -> { final Charset charset = Charset.defaultCharset(); final ByteBuffer byteBuffer = charset.encode("asdf"); final CharBuffer charBuffer = charset.decode(byteBuffer); new StrBuilder().append(charBuffer, 933, 654); }); } @Test void testAppendTakingTwoIntsWithZeroThrowsStringIndexOutOfBoundsException() { assertThrows(StringIndexOutOfBoundsException.class, () -> { final Charset charset = Charset.defaultCharset(); final ByteBuffer byteBuffer = charset.encode("end < start"); final CharBuffer charBuffer = charset.decode(byteBuffer); new StrBuilder(630).append(charBuffer, 0, 630); }); } @Test void testAppendToCharBuffer() throws Exception { final StrBuilder sb = new StrBuilder("1234567890"); final String text = "Test "; final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length()); buffer.put(text); sb.appendTo(buffer); buffer.flip(); assertEquals("Test 1234567890", buffer.toString()); } @Test void testAppendToStringBuffer() throws Exception { final StrBuilder sb = new StrBuilder("1234567890"); final StringBuilder buffer = new StringBuilder("Test "); sb.appendTo(buffer); assertEquals("Test 1234567890", buffer.toString()); } @Test void testAppendToStringBuilder() throws Exception { final StrBuilder sb = new StrBuilder("1234567890"); final StringBuilder builder = new StringBuilder("Test "); sb.appendTo(builder); assertEquals("Test 1234567890", builder.toString()); } @Test void testAppendToWriter() throws Exception { final StrBuilder sb = new StrBuilder("1234567890"); final StringWriter writer = new StringWriter(); writer.append("Test "); sb.appendTo(writer); assertEquals("Test 1234567890", writer.toString()); } @Test void testAsBuilder() { final StrBuilder sb = new StrBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor"); assertEquals(sb.toString(), sb.build()); } @Test void testAsReader() throws Exception { final StrBuilder sb = new StrBuilder("some text"); try (Reader reader = sb.asReader()) { assertTrue(reader.ready()); final char[] buf = new char[40]; assertEquals(9, reader.read(buf)); assertEquals("some text", new String(buf, 0, 9)); assertEquals(-1, reader.read()); assertFalse(reader.ready()); assertEquals(0, reader.skip(2)); assertEquals(0, reader.skip(-1)); assertTrue(reader.markSupported()); } try (Reader reader = sb.asReader()) { assertEquals('s', reader.read()); reader.mark(-1); final char[] array = new char[3]; assertEquals(3, reader.read(array, 0, 3)); assertEquals('o', array[0]); assertEquals('m', array[1]); assertEquals('e', array[2]); reader.reset(); assertEquals(1, reader.read(array, 1, 1)); assertEquals('o', array[0]); assertEquals('o', array[1]); assertEquals('e', array[2]); assertEquals(2, reader.skip(2)); assertEquals(' ', reader.read()); assertTrue(reader.ready()); reader.close(); assertTrue(reader.ready()); } try (Reader reader = sb.asReader()) { char[] array = new char[3]; try { reader.read(array, -1, 0); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } try { reader.read(array, 0, -1); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } try { reader.read(array, 100, 1); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } try { reader.read(array, 0, 100); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } try { reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } assertEquals(0, reader.read(array, 0, 0)); assertEquals(0, array[0]); assertEquals(0, array[1]); assertEquals(0, array[2]); reader.skip(9); assertEquals(-1, reader.read(array, 0, 1)); reader.reset(); array = new char[30]; assertEquals(9, reader.read(array, 0, 30)); } } @Test void testAsTokenizer() throws Exception { // from Javadoc final StrBuilder b = new StrBuilder(); b.append("a b "); final StrTokenizer t = b.asTokenizer(); final String[] tokens1 = t.getTokenArray(); assertEquals(2, tokens1.length); assertEquals("a", tokens1[0]); assertEquals("b", tokens1[1]); assertEquals(2, t.size()); b.append("c d "); final String[] tokens2 = t.getTokenArray(); assertEquals(2, tokens2.length); assertEquals("a", tokens2[0]); assertEquals("b", tokens2[1]); assertEquals(2, t.size()); assertEquals("a", t.next()); assertEquals("b", t.next()); t.reset(); final String[] tokens3 = t.getTokenArray(); assertEquals(4, tokens3.length); assertEquals("a", tokens3[0]); assertEquals("b", tokens3[1]); assertEquals("c", tokens3[2]); assertEquals("d", tokens3[3]); assertEquals(4, t.size()); assertEquals("a", t.next()); assertEquals("b", t.next()); assertEquals("c", t.next()); assertEquals("d", t.next()); assertEquals("a b c d ", t.getContent()); } @Test void testAsWriter() throws Exception { final StrBuilder sb = new StrBuilder("base"); try (Writer writer = sb.asWriter()) { writer.write('l'); assertEquals("basel", sb.toString()); writer.write(new char[] { 'i', 'n' }); assertEquals("baselin", sb.toString()); writer.write(new char[] { 'n', 'e', 'r' }, 1, 2); assertEquals("baseliner", sb.toString()); writer.write(" rout"); assertEquals("baseliner rout", sb.toString()); writer.write("ping that server", 1, 3); assertEquals("baseliner routing", sb.toString()); writer.flush(); // no effect assertEquals("baseliner routing", sb.toString()); writer.close(); // no effect assertEquals("baseliner routing", sb.toString()); writer.write(" hi"); // works after close assertEquals("baseliner routing hi", sb.toString()); sb.setLength(4); // mix and match writer.write('d'); assertEquals("based", sb.toString()); } } @Test void testCapacity() { final StrBuilder sb = new StrBuilder(); assertEquals(sb.buffer.length, sb.capacity()); sb.append("HelloWorldHelloWorldHelloWorldHelloWorld"); assertEquals(sb.buffer.length, sb.capacity()); } @Test void testCapacityAndLength() { final StrBuilder sb = new StrBuilder(); assertEquals(32, sb.capacity()); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.ensureCapacity(32); assertTrue(sb.capacity() >= 32); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.append("foo"); assertTrue(sb.capacity() >= 32); assertEquals(3, sb.length()); assertEquals(3, sb.size()); assertFalse(sb.isEmpty()); sb.clear(); assertTrue(sb.capacity() >= 32); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.append("123456789012345678901234567890123"); assertTrue(sb.capacity() > 32); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); sb.ensureCapacity(16); assertTrue(sb.capacity() > 16); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); sb.minimizeCapacity(); assertEquals(33, sb.capacity()); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1)); sb.setLength(33); assertEquals(33, sb.capacity()); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); sb.setLength(16); assertTrue(sb.capacity() >= 16); assertEquals(16, sb.length()); assertEquals(16, sb.size()); assertEquals("1234567890123456", sb.toString()); assertFalse(sb.isEmpty()); sb.setLength(32); assertTrue(sb.capacity() >= 32); assertEquals(32, sb.length()); assertEquals(32, sb.size()); assertEquals("1234567890123456\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sb.toString()); assertFalse(sb.isEmpty()); sb.setLength(0); assertTrue(sb.capacity() >= 32); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); } @Test void testChaining() { final StrBuilder sb = new StrBuilder(); assertSame(sb, sb.setNewLineText(null)); assertSame(sb, sb.setNullText(null)); assertSame(sb, sb.setLength(1)); assertSame(sb, sb.setCharAt(0, 'a')); assertSame(sb, sb.ensureCapacity(0)); assertSame(sb, sb.minimizeCapacity()); assertSame(sb, sb.clear()); assertSame(sb, sb.reverse()); assertSame(sb, sb.trim()); } @Test void testCharAt() { final StrBuilder sb = new StrBuilder(); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1)); sb.append("foo"); assertEquals('f', sb.charAt(0)); assertEquals('o', sb.charAt(1)); assertEquals('o', sb.charAt(2)); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1)); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(3)); } @Test void testClear() { final StrBuilder sb = new StrBuilder(); sb.append("Hello"); sb.clear(); assertEquals(0, sb.length()); assertTrue(sb.buffer.length >= 5); } @Test void testConstructors() { final StrBuilder sb0 = new StrBuilder(); assertEquals(32, sb0.capacity()); assertEquals(0, sb0.length()); assertEquals(0, sb0.size()); final StrBuilder sb1 = new StrBuilder(32); assertEquals(32, sb1.capacity()); assertEquals(0, sb1.length()); assertEquals(0, sb1.size()); final StrBuilder sb2 = new StrBuilder(0); assertEquals(32, sb2.capacity()); assertEquals(0, sb2.length()); assertEquals(0, sb2.size()); final StrBuilder sb3 = new StrBuilder(-1); assertEquals(32, sb3.capacity()); assertEquals(0, sb3.length()); assertEquals(0, sb3.size()); final StrBuilder sb4 = new StrBuilder(1); assertEquals(1, sb4.capacity()); assertEquals(0, sb4.length()); assertEquals(0, sb4.size()); final StrBuilder sb5 = new StrBuilder((String) null); assertEquals(32, sb5.capacity()); assertEquals(0, sb5.length()); assertEquals(0, sb5.size()); final StrBuilder sb6 = new StrBuilder(""); assertEquals(32, sb6.capacity()); assertEquals(0, sb6.length()); assertEquals(0, sb6.size()); final StrBuilder sb7 = new StrBuilder("foo"); assertEquals(35, sb7.capacity()); assertEquals(3, sb7.length()); assertEquals(3, sb7.size()); } @Test void testContains_char() { final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz"); assertTrue(sb.contains('a')); assertTrue(sb.contains('o')); assertTrue(sb.contains('z')); assertFalse(sb.contains('1')); } @Test void testContains_String() { final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz"); assertTrue(sb.contains("a")); assertTrue(sb.contains("pq")); assertTrue(sb.contains("z")); assertFalse(sb.contains("zyx")); assertFalse(sb.contains((String) null)); } @Test void testContains_StrMatcher() { StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz"); assertTrue(sb.contains(StrMatcher.charMatcher('a'))); assertTrue(sb.contains(StrMatcher.stringMatcher("pq"))); assertTrue(sb.contains(StrMatcher.charMatcher('z'))); assertFalse(sb.contains(StrMatcher.stringMatcher("zy"))); assertFalse(sb.contains((StrMatcher) null)); sb = new StrBuilder(); assertFalse(sb.contains(A_NUMBER_MATCHER)); sb.append("B A1 C"); assertTrue(sb.contains(A_NUMBER_MATCHER)); } @Test void testDeleteAll_char() { StrBuilder sb = new StrBuilder("abcbccba"); sb.deleteAll('X'); assertEquals("abcbccba", sb.toString()); sb.deleteAll('a'); assertEquals("bcbccb", sb.toString()); sb.deleteAll('c'); assertEquals("bbb", sb.toString()); sb.deleteAll('b'); assertEquals("", sb.toString()); sb = new StrBuilder(""); sb.deleteAll('b'); assertEquals("", sb.toString()); } @Test void testDeleteAll_String() { StrBuilder sb = new StrBuilder("abcbccba"); sb.deleteAll((String) null); assertEquals("abcbccba", sb.toString()); sb.deleteAll(""); assertEquals("abcbccba", sb.toString()); sb.deleteAll("X"); assertEquals("abcbccba", sb.toString()); sb.deleteAll("a"); assertEquals("bcbccb", sb.toString()); sb.deleteAll("c"); assertEquals("bbb", sb.toString()); sb.deleteAll("b"); assertEquals("", sb.toString()); sb = new StrBuilder("abcbccba"); sb.deleteAll("bc"); assertEquals("acba", sb.toString()); sb = new StrBuilder(""); sb.deleteAll("bc"); assertEquals("", sb.toString()); } @Test void testDeleteAll_StrMatcher() { StrBuilder sb = new StrBuilder("A0xA1A2yA3"); sb.deleteAll((StrMatcher) null); assertEquals("A0xA1A2yA3", sb.toString()); sb.deleteAll(A_NUMBER_MATCHER); assertEquals("xy", sb.toString()); sb = new StrBuilder("Ax1"); sb.deleteAll(A_NUMBER_MATCHER); assertEquals("Ax1", sb.toString()); sb = new StrBuilder(""); sb.deleteAll(A_NUMBER_MATCHER); assertEquals("", sb.toString()); } @Test void testDeleteCharAt() { final StrBuilder sb = new StrBuilder("abc"); sb.deleteCharAt(0); assertEquals("bc", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.deleteCharAt(1000)); } @Test void testDeleteCharAtWithNegative() { assertThrows(StringIndexOutOfBoundsException.class, () -> new StrBuilder().deleteCharAt(-1258)); } @Test void testDeleteFirst_char() { StrBuilder sb = new StrBuilder("abcba"); sb.deleteFirst('X'); assertEquals("abcba", sb.toString()); sb.deleteFirst('a'); assertEquals("bcba", sb.toString()); sb.deleteFirst('c'); assertEquals("bba", sb.toString()); sb.deleteFirst('b'); assertEquals("ba", sb.toString()); sb = new StrBuilder(""); sb.deleteFirst('b'); assertEquals("", sb.toString()); } @Test void testDeleteFirst_String() { StrBuilder sb = new StrBuilder("abcbccba"); sb.deleteFirst((String) null); assertEquals("abcbccba", sb.toString()); sb.deleteFirst(""); assertEquals("abcbccba", sb.toString()); sb.deleteFirst("X"); assertEquals("abcbccba", sb.toString()); sb.deleteFirst("a"); assertEquals("bcbccba", sb.toString()); sb.deleteFirst("c"); assertEquals("bbccba", sb.toString()); sb.deleteFirst("b"); assertEquals("bccba", sb.toString()); sb = new StrBuilder("abcbccba"); sb.deleteFirst("bc"); assertEquals("abccba", sb.toString()); sb = new StrBuilder(""); sb.deleteFirst("bc"); assertEquals("", sb.toString()); } @Test void testDeleteFirst_StrMatcher() { StrBuilder sb = new StrBuilder("A0xA1A2yA3"); sb.deleteFirst((StrMatcher) null); assertEquals("A0xA1A2yA3", sb.toString()); sb.deleteFirst(A_NUMBER_MATCHER); assertEquals("xA1A2yA3", sb.toString()); sb = new StrBuilder("Ax1"); sb.deleteFirst(A_NUMBER_MATCHER); assertEquals("Ax1", sb.toString()); sb = new StrBuilder(""); sb.deleteFirst(A_NUMBER_MATCHER); assertEquals("", sb.toString()); } @Test void testDeleteIntInt() { final StrBuilder sb = new StrBuilder("abc"); sb.delete(0, 1); assertEquals("bc", sb.toString()); sb.delete(1, 2); assertEquals("b", sb.toString()); sb.delete(0, 1); assertEquals("", sb.toString()); sb.delete(0, 1000); assertEquals("", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(1, 2)); assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(-1, 1)); assertThrows(IndexOutOfBoundsException.class, () -> new StrBuilder("anything").delete(2, 1)); } @Test void testEndsWith() { final StrBuilder sb = new StrBuilder(); assertFalse(sb.endsWith("a")); assertFalse(sb.endsWith("c")); assertTrue(sb.endsWith("")); assertFalse(sb.endsWith(null)); sb.append("abc"); assertTrue(sb.endsWith("c")); assertTrue(sb.endsWith("bc")); assertTrue(sb.endsWith("abc")); assertFalse(sb.endsWith("cba")); assertFalse(sb.endsWith("abcd")); assertFalse(sb.endsWith(" abc")); assertFalse(sb.endsWith("abc ")); } @Test void testEnsureCapacity() { final StrBuilder sb = new StrBuilder(); sb.ensureCapacity(2); assertTrue(sb.capacity() >= 2); sb.ensureCapacity(-1); assertTrue(sb.capacity() >= 0); sb.append("HelloWorld"); sb.ensureCapacity(40); assertTrue(sb.capacity() >= 40); } @Test void testEquals() { final StrBuilder sb1 = new StrBuilder(); final StrBuilder sb2 = new StrBuilder(); assertTrue(sb1.equals(sb2)); assertTrue(sb1.equals(sb1)); assertTrue(sb2.equals(sb2)); assertEquals(sb1, (Object) sb2); sb1.append("abc"); assertFalse(sb1.equals(sb2)); assertNotEquals(sb1, (Object) sb2); sb2.append("ABC"); assertFalse(sb1.equals(sb2)); assertNotEquals(sb1, (Object) sb2); sb2.clear().append("abc"); assertTrue(sb1.equals(sb2)); assertEquals(sb1, (Object) sb2); assertNotEquals(sb1, Integer.valueOf(1)); assertNotEquals("abc", sb1); } @Test void testEqualsIgnoreCase() { final StrBuilder sb1 = new StrBuilder(); final StrBuilder sb2 = new StrBuilder(); assertTrue(sb1.equalsIgnoreCase(sb1)); assertTrue(sb1.equalsIgnoreCase(sb2)); assertTrue(sb2.equalsIgnoreCase(sb2)); sb1.append("abc"); assertFalse(sb1.equalsIgnoreCase(sb2)); sb2.append("ABC"); assertTrue(sb1.equalsIgnoreCase(sb2)); sb2.clear().append("abc"); assertTrue(sb1.equalsIgnoreCase(sb2)); assertTrue(sb1.equalsIgnoreCase(sb1)); assertTrue(sb2.equalsIgnoreCase(sb2)); sb2.clear().append("aBc"); assertTrue(sb1.equalsIgnoreCase(sb2)); } @Test void testGetChars() { final StrBuilder sb = new StrBuilder(); char[] input = new char[10]; char[] a = sb.getChars(input); assertSame(input, a); assertArrayEquals(new char[10], a); sb.append("junit"); a = sb.getChars(input); assertSame(input, a); assertArrayEquals(new char[] { 'j', 'u', 'n', 'i', 't', 0, 0, 0, 0, 0 }, a); a = sb.getChars(null); assertNotSame(input, a); assertEquals(5, a.length); assertArrayEquals("junit".toCharArray(), a); input = new char[5]; a = sb.getChars(input); assertSame(input, a); input = new char[4]; a = sb.getChars(input); assertNotSame(input, a); } @Test void testGetCharsIntIntCharArrayInt() { final StrBuilder sb = new StrBuilder(); sb.append("junit"); char[] a = new char[5]; sb.getChars(0, 5, a, 0); assertArrayEquals(new char[] { 'j', 'u', 'n', 'i', 't' }, a); a = new char[5]; sb.getChars(0, 2, a, 3); assertArrayEquals(new char[] { 0, 0, 0, 'j', 'u' }, a); try { sb.getChars(-1, 0, a, 0); fail("no exception"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.getChars(0, -1, a, 0); fail("no exception"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.getChars(0, 20, a, 0); fail("no exception"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.getChars(4, 2, a, 0); fail("no exception"); } catch (final IndexOutOfBoundsException e) { // expected } } @Test void testGetSetNewLineText() { final StrBuilder sb = new StrBuilder(); assertNull(sb.getNewLineText()); sb.setNewLineText("#"); assertEquals("#", sb.getNewLineText()); sb.setNewLineText(""); assertEquals("", sb.getNewLineText()); sb.setNewLineText((String) null); assertNull(sb.getNewLineText()); } @Test void testGetSetNullText() { final StrBuilder sb = new StrBuilder(); assertNull(sb.getNullText()); sb.setNullText("null"); assertEquals("null", sb.getNullText()); sb.setNullText(""); assertNull(sb.getNullText()); sb.setNullText("NULL"); assertEquals("NULL", sb.getNullText()); sb.setNullText((String) null); assertNull(sb.getNullText()); } @Test void testHashCode() { final StrBuilder sb = new StrBuilder(); final int hc1a = sb.hashCode(); final int hc1b = sb.hashCode(); assertEquals(0, hc1a); assertEquals(hc1a, hc1b); sb.append("abc"); final int hc2a = sb.hashCode(); final int hc2b = sb.hashCode(); assertTrue(hc2a != 0); assertEquals(hc2a, hc2b); } @Test void testIndexOf_char() { final StrBuilder sb = new StrBuilder("abab"); assertEquals(0, sb.indexOf('a')); // should work like String#indexOf assertEquals("abab".indexOf('a'), sb.indexOf('a')); assertEquals(1, sb.indexOf('b')); assertEquals("abab".indexOf('b'), sb.indexOf('b')); assertEquals(-1, sb.indexOf('z')); } @Test void testIndexOf_char_int() { StrBuilder sb = new StrBuilder("abab"); assertEquals(0, sb.indexOf('a', -1)); assertEquals(0, sb.indexOf('a', 0)); assertEquals(2, sb.indexOf('a', 1)); assertEquals(-1, sb.indexOf('a', 4)); assertEquals(-1, sb.indexOf('a', 5)); // should work like String#indexOf assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1)); assertEquals(3, sb.indexOf('b', 2)); assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2)); assertEquals(-1, sb.indexOf('z', 2)); sb = new StrBuilder("xyzabc"); assertEquals(2, sb.indexOf('z', 0)); assertEquals(-1, sb.indexOf('z', 3)); } @Test void testIndexOf_String() { final StrBuilder sb = new StrBuilder("abab"); assertEquals(0, sb.indexOf("a")); // should work like String#indexOf assertEquals("abab".indexOf("a"), sb.indexOf("a")); assertEquals(0, sb.indexOf("ab")); // should work like String#indexOf assertEquals("abab".indexOf("ab"), sb.indexOf("ab")); assertEquals(1, sb.indexOf("b")); assertEquals("abab".indexOf("b"), sb.indexOf("b")); assertEquals(1, sb.indexOf("ba")); assertEquals("abab".indexOf("ba"), sb.indexOf("ba")); assertEquals(-1, sb.indexOf("z")); assertEquals(-1, sb.indexOf((String) null)); } @Test void testIndexOf_String_int() { StrBuilder sb = new StrBuilder("abab"); assertEquals(0, sb.indexOf("a", -1)); assertEquals(0, sb.indexOf("a", 0)); assertEquals(2, sb.indexOf("a", 1)); assertEquals(2, sb.indexOf("a", 2)); assertEquals(-1, sb.indexOf("a", 3)); assertEquals(-1, sb.indexOf("a", 4)); assertEquals(-1, sb.indexOf("a", 5)); assertEquals(-1, sb.indexOf("abcdef", 0)); assertEquals(0, sb.indexOf("", 0)); assertEquals(1, sb.indexOf("", 1)); // should work like String#indexOf assertEquals("abab".indexOf("a", 1), sb.indexOf("a", 1)); assertEquals(2, sb.indexOf("ab", 1)); // should work like String#indexOf assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1)); assertEquals(3, sb.indexOf("b", 2)); assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2)); assertEquals(1, sb.indexOf("ba", 1)); assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2)); assertEquals(-1, sb.indexOf("z", 2)); sb = new StrBuilder("xyzabc"); assertEquals(2, sb.indexOf("za", 0)); assertEquals(-1, sb.indexOf("za", 3)); assertEquals(-1, sb.indexOf((String) null, 2)); } @Test void testIndexOf_StrMatcher() { final StrBuilder sb = new StrBuilder(); assertEquals(-1, sb.indexOf((StrMatcher) null)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'))); sb.append("ab bd"); assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'))); assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'))); assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher())); assertEquals(4, sb.indexOf(StrMatcher.charMatcher('d'))); assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher())); assertEquals(-1, sb.indexOf((StrMatcher) null)); sb.append(" A1 junction"); assertEquals(6, sb.indexOf(A_NUMBER_MATCHER)); } @Test void testIndexOf_StrMatcher_int() { final StrBuilder sb = new StrBuilder(); assertEquals(-1, sb.indexOf((StrMatcher) null, 2)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 0)); sb.append("ab bd"); assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), -2)); assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), 0)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 20)); assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), -1)); assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 0)); assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 1)); assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 2)); assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 3)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 4)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 5)); assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 6)); assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), -2)); assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 0)); assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 2)); assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 4)); assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 20)); assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher(), 0)); assertEquals(-1, sb.indexOf((StrMatcher) null, 0)); sb.append(" A1 junction with A2"); assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5)); assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6)); assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7)); assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22)); assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23)); assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24)); } @Test void testIndexOfLang294() { final StrBuilder sb = new StrBuilder("onetwothree"); sb.deleteFirst("three"); assertEquals(-1, sb.indexOf("three")); } @Test void testIsEmpty() { final StrBuilder sb = new StrBuilder(); assertTrue(sb.isEmpty()); sb.append("Hello"); assertFalse(sb.isEmpty()); sb.clear(); assertTrue(sb.isEmpty()); } @Test void testLang294() { final StrBuilder sb = new StrBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n"); sb.deleteAll("\n%BLAH%"); assertEquals("\nDo more stuff\neven more stuff\n", sb.toString()); } @Test void testLang295() { final StrBuilder sb = new StrBuilder("onetwothree"); sb.deleteFirst("three"); assertFalse(sb.contains('h'), "The contains(char) method is looking beyond the end of the string"); assertEquals(-1, sb.indexOf('h'), "The indexOf(char) method is looking beyond the end of the string"); } @Test void testLang412Left() { final StrBuilder sb = new StrBuilder(); sb.appendFixedWidthPadLeft(null, 10, '*'); assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadLeft correctly"); } @Test void testLang412Right() { final StrBuilder sb = new StrBuilder(); sb.appendFixedWidthPadRight(null, 10, '*'); assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadRight correctly"); } @Test void testLastIndexOf_char() { final StrBuilder sb = new StrBuilder("abab"); assertEquals(2, sb.lastIndexOf('a')); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf('a'), sb.lastIndexOf('a')); assertEquals(3, sb.lastIndexOf('b')); assertEquals("abab".lastIndexOf('b'), sb.lastIndexOf('b')); assertEquals(-1, sb.lastIndexOf('z')); } @Test void testLastIndexOf_char_int() { StrBuilder sb = new StrBuilder("abab"); assertEquals(-1, sb.lastIndexOf('a', -1)); assertEquals(0, sb.lastIndexOf('a', 0)); assertEquals(0, sb.lastIndexOf('a', 1)); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1)); assertEquals(1, sb.lastIndexOf('b', 2)); assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2)); assertEquals(-1, sb.lastIndexOf('z', 2)); sb = new StrBuilder("xyzabc"); assertEquals(2, sb.lastIndexOf('z', sb.length())); assertEquals(-1, sb.lastIndexOf('z', 1)); } @Test void testLastIndexOf_String() { final StrBuilder sb = new StrBuilder("abab"); assertEquals(2, sb.lastIndexOf("a")); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a")); assertEquals(2, sb.lastIndexOf("ab")); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab")); assertEquals(3, sb.lastIndexOf("b")); assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b")); assertEquals(1, sb.lastIndexOf("ba")); assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba")); assertEquals(-1, sb.lastIndexOf("z")); assertEquals(-1, sb.lastIndexOf((String) null)); } @Test void testLastIndexOf_String_int() { StrBuilder sb = new StrBuilder("abab"); assertEquals(-1, sb.lastIndexOf("a", -1)); assertEquals(0, sb.lastIndexOf("a", 0)); assertEquals(0, sb.lastIndexOf("a", 1)); assertEquals(2, sb.lastIndexOf("a", 2)); assertEquals(2, sb.lastIndexOf("a", 3)); assertEquals(2, sb.lastIndexOf("a", 4)); assertEquals(2, sb.lastIndexOf("a", 5)); assertEquals(-1, sb.lastIndexOf("abcdef", 3)); assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3)); assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1)); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1)); assertEquals(0, sb.lastIndexOf("ab", 1)); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1)); assertEquals(1, sb.lastIndexOf("b", 2)); assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2)); assertEquals(1, sb.lastIndexOf("ba", 2)); assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2)); assertEquals(-1, sb.lastIndexOf("z", 2)); sb = new StrBuilder("xyzabc"); assertEquals(2, sb.lastIndexOf("za", sb.length())); assertEquals(-1, sb.lastIndexOf("za", 1)); assertEquals(-1, sb.lastIndexOf((String) null, 2)); } @Test void testLastIndexOf_StrMatcher() { final StrBuilder sb = new StrBuilder(); assertEquals(-1, sb.lastIndexOf((StrMatcher) null)); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'))); sb.append("ab bd"); assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'))); assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'))); assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher())); assertEquals(4, sb.lastIndexOf(StrMatcher.charMatcher('d'))); assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher())); assertEquals(-1, sb.lastIndexOf((StrMatcher) null)); sb.append(" A1 junction"); assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER)); } @Test void testLastIndexOf_StrMatcher_int() { final StrBuilder sb = new StrBuilder(); assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 2)); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2)); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0)); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -1)); sb.append("ab bd"); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -2)); assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0)); assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2)); assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 20)); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), -1)); assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 0)); assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 1)); assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 2)); assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 3)); assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 4)); assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 5)); assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 6)); assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), -2)); assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), 0)); assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 2)); assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 4)); assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 20)); assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher(), 0)); assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 0)); sb.append(" A1 junction with A2"); assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5)); assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1 // is outside // bounds assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7)); assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22)); assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2 // is outside // bounds assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24)); } @Test void testLeftString() { final StrBuilder sb = new StrBuilder("left right"); assertEquals("left", sb.leftString(4)); assertEquals("", sb.leftString(0)); assertEquals("", sb.leftString(-5)); assertEquals("left right", sb.leftString(15)); } @Test void testLength() { final StrBuilder sb = new StrBuilder(); assertEquals(0, sb.length()); sb.append("Hello"); assertEquals(5, sb.length()); } @Test void testMidString() { final StrBuilder sb = new StrBuilder("hello goodbye hello"); assertEquals("goodbye", sb.midString(6, 7)); assertEquals("hello", sb.midString(0, 5)); assertEquals("hello", sb.midString(-5, 5)); assertEquals("", sb.midString(0, -1)); assertEquals("", sb.midString(20, 2)); assertEquals("hello", sb.midString(14, 22)); } @Test void testMinimizeCapacity() { final StrBuilder sb = new StrBuilder(); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); sb.append("HelloWorld"); sb.minimizeCapacity(); assertEquals(10, sb.capacity()); } @Test void testReadFromCharBuffer() throws Exception { String s = ""; for (int i = 0; i < 100; ++i) { final StrBuilder sb = new StrBuilder(); final int len = sb.readFrom(CharBuffer.wrap(s)); assertEquals(s.length(), len); assertEquals(s, sb.toString()); s += Integer.toString(i); } } @Test void testReadFromCharBufferAppendsToEnd() throws Exception { final StrBuilder sb = new StrBuilder("Test"); sb.readFrom(CharBuffer.wrap(" 123")); assertEquals("Test 123", sb.toString()); } @Test void testReadFromReadable() throws Exception { String s = ""; for (int i = 0; i < 100; ++i) { final StrBuilder sb = new StrBuilder(); final int len = sb.readFrom(new MockReadable(s)); assertEquals(s.length(), len); assertEquals(s, sb.toString()); s += Integer.toString(i); } } @Test void testReadFromReadableAppendsToEnd() throws Exception { final StrBuilder sb = new StrBuilder("Test"); sb.readFrom(new MockReadable(" 123")); assertEquals("Test 123", sb.toString()); } @Test void testReadFromReader() throws Exception { String s = ""; for (int i = 0; i < 100; ++i) { final StrBuilder sb = new StrBuilder(); final int len = sb.readFrom(new StringReader(s)); assertEquals(s.length(), len); assertEquals(s, sb.toString()); s += Integer.toString(i); } } @Test void testReadFromReaderAppendsToEnd() throws Exception { final StrBuilder sb = new StrBuilder("Test"); sb.readFrom(new StringReader(" 123")); assertEquals("Test 123", sb.toString()); } @Test void testReplace_int_int_String() { StrBuilder sb = new StrBuilder("abc"); sb.replace(0, 1, "d"); assertEquals("dbc", sb.toString()); sb.replace(0, 1, "aaa"); assertEquals("aaabc", sb.toString()); sb.replace(0, 3, ""); assertEquals("bc", sb.toString()); sb.replace(1, 2, (String) null); assertEquals("b", sb.toString()); sb.replace(1, 1000, "text"); assertEquals("btext", sb.toString()); sb.replace(0, 1000, "text"); assertEquals("text", sb.toString()); sb = new StrBuilder("atext"); sb.replace(1, 1, "ny"); assertEquals("anytext", sb.toString()); try { sb.replace(2, 1, "anything"); fail("Expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } sb = new StrBuilder(); try { sb.replace(1, 2, "anything"); fail("Expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } try { sb.replace(-1, 1, "anything"); fail("Expected IndexOutOfBoundsException"); } catch (final IndexOutOfBoundsException e) { // expected } } @Test void testReplace_StrMatcher_String_int_int_int_VaryCount() { StrBuilder sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1); assertEquals("-x--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 0); assertEquals("aaxaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 1); assertEquals("-xaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 2); assertEquals("-x-aayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 3); assertEquals("-x--yaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 4); assertEquals("-x--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 5); assertEquals("-x--y-", sb.toString()); } @Test void testReplace_StrMatcher_String_int_int_int_VaryEndIndex() { StrBuilder sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 0, -1); assertEquals("aaxaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 2, -1); assertEquals("-xaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 3, -1); assertEquals("-xaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 4, -1); assertEquals("-xaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 5, -1); assertEquals("-x-aayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 6, -1); assertEquals("-x-aayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 7, -1); assertEquals("-x--yaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 8, -1); assertEquals("-x--yaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 9, -1); assertEquals("-x--yaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1); assertEquals("-x--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 1000, -1); assertEquals("-x--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); try { sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, 1, -1); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } assertEquals("aaxaaaayaa", sb.toString()); } @Test void testReplace_StrMatcher_String_int_int_int_VaryMatcher() { StrBuilder sb = new StrBuilder("abcbccba"); sb.replace((StrMatcher) null, "x", 0, sb.length(), -1); assertEquals("abcbccba", sb.toString()); sb.replace(StrMatcher.charMatcher('a'), "x", 0, sb.length(), -1); assertEquals("xbcbccbx", sb.toString()); sb.replace(StrMatcher.stringMatcher("cb"), "x", 0, sb.length(), -1); assertEquals("xbxcxx", sb.toString()); sb = new StrBuilder("A1-A2A3-A4"); sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1); assertEquals("***-******-***", sb.toString()); sb = new StrBuilder(); sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1); assertEquals("", sb.toString()); } @Test void testReplace_StrMatcher_String_int_int_int_VaryReplace() { StrBuilder sb = new StrBuilder("abcbccba"); sb.replace(StrMatcher.stringMatcher("cb"), "cb", 0, sb.length(), -1); assertEquals("abcbccba", sb.toString()); sb = new StrBuilder("abcbccba"); sb.replace(StrMatcher.stringMatcher("cb"), "-", 0, sb.length(), -1); assertEquals("ab-c-a", sb.toString()); sb = new StrBuilder("abcbccba"); sb.replace(StrMatcher.stringMatcher("cb"), "+++", 0, sb.length(), -1); assertEquals("ab+++c+++a", sb.toString()); sb = new StrBuilder("abcbccba"); sb.replace(StrMatcher.stringMatcher("cb"), "", 0, sb.length(), -1); assertEquals("abca", sb.toString()); sb = new StrBuilder("abcbccba"); sb.replace(StrMatcher.stringMatcher("cb"), null, 0, sb.length(), -1); assertEquals("abca", sb.toString()); } @Test void testReplace_StrMatcher_String_int_int_int_VaryStartIndex() { StrBuilder sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, sb.length(), -1); assertEquals("-x--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 1, sb.length(), -1); assertEquals("aax--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, sb.length(), -1); assertEquals("aax--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 3, sb.length(), -1); assertEquals("aax--y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 4, sb.length(), -1); assertEquals("aaxa-ay-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 5, sb.length(), -1); assertEquals("aaxaa-y-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 6, sb.length(), -1); assertEquals("aaxaaaay-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 7, sb.length(), -1); assertEquals("aaxaaaay-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 8, sb.length(), -1); assertEquals("aaxaaaay-", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 9, sb.length(), -1); assertEquals("aaxaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); sb.replace(StrMatcher.stringMatcher("aa"), "-", 10, sb.length(), -1); assertEquals("aaxaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); try { sb.replace(StrMatcher.stringMatcher("aa"), "-", 11, sb.length(), -1); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } assertEquals("aaxaaaayaa", sb.toString()); sb = new StrBuilder("aaxaaaayaa"); try { sb.replace(StrMatcher.stringMatcher("aa"), "-", -1, sb.length(), -1); fail("Exception expected!"); } catch (final IndexOutOfBoundsException ex) { // expected } assertEquals("aaxaaaayaa", sb.toString()); } @Test void testReplaceAll_char_char() { final StrBuilder sb = new StrBuilder("abcbccba"); sb.replaceAll('x', 'y'); assertEquals("abcbccba", sb.toString()); sb.replaceAll('a', 'd'); assertEquals("dbcbccbd", sb.toString()); sb.replaceAll('b', 'e'); assertEquals("dececced", sb.toString()); sb.replaceAll('c', 'f'); assertEquals("defeffed", sb.toString()); sb.replaceAll('d', 'd'); assertEquals("defeffed", sb.toString()); } @Test void testReplaceAll_String_String() { StrBuilder sb = new StrBuilder("abcbccba"); sb.replaceAll((String) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceAll((String) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll("", null); assertEquals("abcbccba", sb.toString()); sb.replaceAll("", "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll("x", "y"); assertEquals("abcbccba", sb.toString()); sb.replaceAll("a", "d"); assertEquals("dbcbccbd", sb.toString()); sb.replaceAll("d", null); assertEquals("bcbccb", sb.toString()); sb.replaceAll("cb", "-"); assertEquals("b-c-", sb.toString()); sb = new StrBuilder("abcba"); sb.replaceAll("b", "xbx"); assertEquals("axbxcxbxa", sb.toString()); sb = new StrBuilder("bb"); sb.replaceAll("b", "xbx"); assertEquals("xbxxbx", sb.toString()); } @Test void testReplaceAll_StrMatcher_String() { StrBuilder sb = new StrBuilder("abcbccba"); sb.replaceAll((StrMatcher) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceAll((StrMatcher) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StrMatcher.noneMatcher(), null); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StrMatcher.noneMatcher(), "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StrMatcher.charMatcher('x'), "y"); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StrMatcher.charMatcher('a'), "d"); assertEquals("dbcbccbd", sb.toString()); sb.replaceAll(StrMatcher.charMatcher('d'), null); assertEquals("bcbccb", sb.toString()); sb.replaceAll(StrMatcher.stringMatcher("cb"), "-"); assertEquals("b-c-", sb.toString()); sb = new StrBuilder("abcba"); sb.replaceAll(StrMatcher.charMatcher('b'), "xbx"); assertEquals("axbxcxbxa", sb.toString()); sb = new StrBuilder("bb"); sb.replaceAll(StrMatcher.charMatcher('b'), "xbx"); assertEquals("xbxxbx", sb.toString()); sb = new StrBuilder("A1-A2A3-A4"); sb.replaceAll(A_NUMBER_MATCHER, "***"); assertEquals("***-******-***", sb.toString()); sb = new StrBuilder("Dear X, hello X."); sb.replaceAll(StrMatcher.stringMatcher("X"), "012345678901234567"); assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString()); } @Test void testReplaceFirst_char_char() { final StrBuilder sb = new StrBuilder("abcbccba"); sb.replaceFirst('x', 'y'); assertEquals("abcbccba", sb.toString()); sb.replaceFirst('a', 'd'); assertEquals("dbcbccba", sb.toString()); sb.replaceFirst('b', 'e'); assertEquals("decbccba", sb.toString()); sb.replaceFirst('c', 'f'); assertEquals("defbccba", sb.toString()); sb.replaceFirst('d', 'd'); assertEquals("defbccba", sb.toString()); } @Test void testReplaceFirst_String_String() { StrBuilder sb = new StrBuilder("abcbccba"); sb.replaceFirst((String) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst((String) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("", null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("", "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("x", "y"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("a", "d"); assertEquals("dbcbccba", sb.toString()); sb.replaceFirst("d", null); assertEquals("bcbccba", sb.toString()); sb.replaceFirst("cb", "-"); assertEquals("b-ccba", sb.toString()); sb = new StrBuilder("abcba"); sb.replaceFirst("b", "xbx"); assertEquals("axbxcba", sb.toString()); sb = new StrBuilder("bb"); sb.replaceFirst("b", "xbx"); assertEquals("xbxb", sb.toString()); } @Test void testReplaceFirst_StrMatcher_String() { StrBuilder sb = new StrBuilder("abcbccba"); sb.replaceFirst((StrMatcher) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst((StrMatcher) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StrMatcher.noneMatcher(), null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StrMatcher.noneMatcher(), "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StrMatcher.charMatcher('x'), "y"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StrMatcher.charMatcher('a'), "d"); assertEquals("dbcbccba", sb.toString()); sb.replaceFirst(StrMatcher.charMatcher('d'), null); assertEquals("bcbccba", sb.toString()); sb.replaceFirst(StrMatcher.stringMatcher("cb"), "-"); assertEquals("b-ccba", sb.toString()); sb = new StrBuilder("abcba"); sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx"); assertEquals("axbxcba", sb.toString()); sb = new StrBuilder("bb"); sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx"); assertEquals("xbxb", sb.toString()); sb = new StrBuilder("A1-A2A3-A4"); sb.replaceFirst(A_NUMBER_MATCHER, "***"); assertEquals("***-A2A3-A4", sb.toString()); } @Test void testReverse() { final StrBuilder sb = new StrBuilder(); assertEquals("", sb.reverse().toString()); sb.clear().append(true); assertEquals("eurt", sb.reverse().toString()); assertEquals("true", sb.reverse().toString()); } @Test void testRightString() { final StrBuilder sb = new StrBuilder("left right"); assertEquals("right", sb.rightString(5)); assertEquals("", sb.rightString(0)); assertEquals("", sb.rightString(-5)); assertEquals("left right", sb.rightString(15)); } @Test void testSetCharAt() { final StrBuilder sb = new StrBuilder(); assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(0, 'f')); assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(-1, 'f')); sb.append("foo"); sb.setCharAt(0, 'b'); sb.setCharAt(1, 'a'); sb.setCharAt(2, 'r'); assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(3, '!')); assertEquals("bar", sb.toString()); } @Test void testSetLength() { final StrBuilder sb = new StrBuilder(); sb.append("Hello"); sb.setLength(2); // shorten assertEquals("He", sb.toString()); sb.setLength(2); // no change assertEquals("He", sb.toString()); sb.setLength(3); // lengthen assertEquals("He\0", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1)); } @Test void testSize() { final StrBuilder sb = new StrBuilder(); assertEquals(0, sb.size()); sb.append("Hello"); assertEquals(5, sb.size()); } @Test void testStartsWith() { final StrBuilder sb = new StrBuilder(); assertFalse(sb.startsWith("a")); assertFalse(sb.startsWith(null)); assertTrue(sb.startsWith("")); sb.append("abc"); assertTrue(sb.startsWith("a")); assertTrue(sb.startsWith("ab")); assertTrue(sb.startsWith("abc")); assertFalse(sb.startsWith("cba")); } @Test void testSubSequenceIntInt() { final StrBuilder sb = new StrBuilder("hello goodbye"); // Start index is negative assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(-1, 5)); // End index is negative assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, -1)); // End index greater than length() assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, sb.length() + 1)); // Start index greater then end index assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(3, 2)); // Normal cases assertEquals("hello", sb.subSequence(0, 5)); assertEquals("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6)); assertEquals("goodbye", sb.subSequence(6, 13)); assertEquals("hello goodbye".subSequence(6, 13), sb.subSequence(6, 13)); } @Test void testSubstringInt() { final StrBuilder sb = new StrBuilder("hello goodbye"); assertEquals("goodbye", sb.substring(6)); assertEquals("hello goodbye".substring(6), sb.substring(6)); assertEquals("hello goodbye", sb.substring(0)); assertEquals("hello goodbye".substring(0), sb.substring(0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15)); } @Test void testSubstringIntInt() { final StrBuilder sb = new StrBuilder("hello goodbye"); assertEquals("hello", sb.substring(0, 5)); assertEquals("hello goodbye".substring(0, 6), sb.substring(0, 6)); assertEquals("goodbye", sb.substring(6, 13)); assertEquals("hello goodbye".substring(6, 13), sb.substring(6, 13)); assertEquals("goodbye", sb.substring(6, 20)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1, 5)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15, 20)); } @Test void testToCharArray() { final StrBuilder sb = new StrBuilder(); assertEquals(0, sb.toCharArray().length); char[] a = sb.toCharArray(); assertNotNull(a, "toCharArray() result is null"); assertEquals(0, a.length, "toCharArray() result is too large"); sb.append("junit"); a = sb.toCharArray(); assertEquals(5, a.length, "toCharArray() result incorrect length"); assertArrayEquals("junit".toCharArray(), a, "toCharArray() result does not match"); } @Test void testToCharArrayIntInt() { final StrBuilder sb = new StrBuilder(); assertEquals(0, sb.toCharArray(0, 0).length); sb.append("junit"); char[] a = sb.toCharArray(0, 20); // too large test assertEquals(5, a.length, "toCharArray(int,int) result incorrect length"); assertArrayEquals("junit".toCharArray(), a, "toCharArray(int,int) result does not match"); a = sb.toCharArray(0, 4); assertEquals(4, a.length, "toCharArray(int,int) result incorrect length"); assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match"); a = sb.toCharArray(0, 4); assertEquals(4, a.length, "toCharArray(int,int) result incorrect length"); assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match"); a = sb.toCharArray(0, 1); assertNotNull(a, "toCharArray(int,int) result is null"); assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(-1, 5)); assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(6, 5)); } @Test void testToString() { final StrBuilder sb = new StrBuilder("abc"); assertEquals("abc", sb.toString()); } @Test void testToStringBuffer() { final StrBuilder sb = new StrBuilder(); assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString()); sb.append("junit"); assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString()); } @Test void testToStringBuilder() { final StrBuilder sb = new StrBuilder(); assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString()); sb.append("junit"); assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString()); } @Test void testTrim() { final StrBuilder sb = new StrBuilder(); assertEquals("", sb.reverse().toString()); sb.clear().append(" \u0000 "); assertEquals("", sb.trim().toString()); sb.clear().append(" \u0000 a b c"); assertEquals("a b c", sb.trim().toString()); sb.clear().append("a b c \u0000 "); assertEquals("a b c", sb.trim().toString()); sb.clear().append(" \u0000 a b c \u0000 "); assertEquals("a b c", sb.trim().toString()); sb.clear().append("a b c"); assertEquals("a b c", sb.trim().toString()); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/StrLookupTest.java000066400000000000000000000117721511432740600322640ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.ResourceBundle; import org.junit.jupiter.api.Test; /** * Test class for {@link StrLookup}. * * @deprecated This class will be removed in 2.0. */ @Deprecated class StrLookupTest { @Test void testMapLookup() { final Map map = new HashMap<>(); map.put("key", "value"); map.put("number", 2); assertEquals("value", StrLookup.mapLookup(map).apply("key")); assertEquals("2", StrLookup.mapLookup(map).apply("number")); assertNull(StrLookup.mapLookup(map).apply(null)); assertNull(StrLookup.mapLookup(map).apply("")); assertNull(StrLookup.mapLookup(map).apply("other")); } @Test void testMapLookup_nullMap() { final Map map = null; assertNull(StrLookup.mapLookup(map).apply(null)); assertNull(StrLookup.mapLookup(map).apply("")); assertNull(StrLookup.mapLookup(map).apply("any")); } @Test void testNoneLookup() { assertNull(StrLookup.noneLookup().apply(null)); assertNull(StrLookup.noneLookup().apply("")); assertNull(StrLookup.noneLookup().apply("any")); } @Test void testResourceBundleLookup() { final ResourceBundle map = ResourceBundle.getBundle("org.apache.commons.text.example.testResourceBundleLookup"); assertEquals("value", StrLookup.resourceBundleLookup(map).apply("key")); assertEquals("2", StrLookup.resourceBundleLookup(map).lookup("number")); assertNull(StrLookup.resourceBundleLookup(map).apply(null)); assertNull(StrLookup.resourceBundleLookup(map).apply("")); assertNull(StrLookup.resourceBundleLookup(map).apply("other")); } @Test void testResourceBundleLookup_nullMap() { final ResourceBundle resourceBundle = null; assertNull(StrLookup.resourceBundleLookup(resourceBundle).apply(null)); assertNull(StrLookup.resourceBundleLookup(resourceBundle).apply("")); assertNull(StrLookup.resourceBundleLookup(resourceBundle).apply("any")); } @Test void testSystemPropertiesLookup() { assertEquals(System.getProperty("os.name"), StrLookup.systemPropertiesLookup().apply("os.name")); assertNull(StrLookup.systemPropertiesLookup().apply("")); assertNull(StrLookup.systemPropertiesLookup().apply("other")); assertThrows(NullPointerException.class, () -> StrLookup.systemPropertiesLookup().apply(null)); } /** * Tests that a lookup object for system properties can deal with a full * replacement of the system properties object. This test is related to * LANG-1055. */ @Test void testSystemPropertiesLookupReplacedProperties() { final Properties oldProperties = System.getProperties(); final String osName = "os.name"; final String newOsName = oldProperties.getProperty(osName) + "_changed"; final StrLookup sysLookup = StrLookup.systemPropertiesLookup(); final Properties newProps = new Properties(); newProps.setProperty(osName, newOsName); System.setProperties(newProps); try { assertEquals(newOsName, sysLookup.apply(osName), "Changed properties not detected"); } finally { System.setProperties(oldProperties); } } /** * Tests that a lookup object for system properties sees changes on system * properties. This test is related to LANG-1141. */ @Test void testSystemPropertiesLookupUpdatedProperty() { final String osName = "os.name"; final String oldOs = System.getProperty(osName); final String newOsName = oldOs + "_changed"; final StrLookup sysLookup = StrLookup.systemPropertiesLookup(); System.setProperty(osName, newOsName); try { assertEquals(newOsName, sysLookup.apply(osName), "Changed properties not detected"); } finally { System.setProperty(osName, oldOs); } } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/StrMatcherTest.java000066400000000000000000000214201511432740600323650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import org.junit.jupiter.api.Test; /** * Tests {@link StrMatcher}. * * @deprecated This class will be removed in 2.0. */ @Deprecated class StrMatcherTest { private static final char[] BUFFER1 = "0,1\t2 3\n\r\f\u0000'\"".toCharArray(); private static final char[] BUFFER2 = "abcdef".toCharArray(); static void assertStrMatcherImpl(final String internalSimpleName, final StrMatcher obj) { assertEquals(StrMatcher.class.getName() + "$" + internalSimpleName, obj.getClass().getName()); } static void assertStrMatcherPrefixImpl(final String internalSimpleName, final StrSubstitutor obj) { assertStrMatcherImpl(internalSimpleName, obj.getVariablePrefixMatcher()); } static void assertStrMatcherSuffixImpl(final String internalSimpleName, final StrSubstitutor obj) { assertStrMatcherImpl(internalSimpleName, obj.getVariableSuffixMatcher()); } @Test void testCharMatcher_char() { final StrMatcher matcher = StrMatcher.charMatcher('c'); assertEquals(0, matcher.isMatch(BUFFER2, 0)); assertEquals(0, matcher.isMatch(BUFFER2, 1)); assertEquals(1, matcher.isMatch(BUFFER2, 2)); assertEquals(0, matcher.isMatch(BUFFER2, 3)); assertEquals(0, matcher.isMatch(BUFFER2, 4)); assertEquals(0, matcher.isMatch(BUFFER2, 5)); } @Test void testCharSetMatcher_charArray() { final StrMatcher matcher = StrMatcher.charSetMatcher("ace".toCharArray()); assertEquals(1, matcher.isMatch(BUFFER2, 0)); assertEquals(0, matcher.isMatch(BUFFER2, 1)); assertEquals(1, matcher.isMatch(BUFFER2, 2)); assertEquals(0, matcher.isMatch(BUFFER2, 3)); assertEquals(1, matcher.isMatch(BUFFER2, 4)); assertEquals(0, matcher.isMatch(BUFFER2, 5)); assertSame(StrMatcher.charSetMatcher(), StrMatcher.noneMatcher()); assertSame(StrMatcher.charSetMatcher((char[]) null), StrMatcher.noneMatcher()); StrMatcherTest.assertStrMatcherImpl("CharMatcher", StrMatcher.charSetMatcher("a".toCharArray())); } @Test void testCharSetMatcher_String() { final StrMatcher matcher = StrMatcher.charSetMatcher("ace"); assertEquals(1, matcher.isMatch(BUFFER2, 0)); assertEquals(0, matcher.isMatch(BUFFER2, 1)); assertEquals(1, matcher.isMatch(BUFFER2, 2)); assertEquals(0, matcher.isMatch(BUFFER2, 3)); assertEquals(1, matcher.isMatch(BUFFER2, 4)); assertEquals(0, matcher.isMatch(BUFFER2, 5)); assertSame(StrMatcher.charSetMatcher(""), StrMatcher.noneMatcher()); assertSame(StrMatcher.charSetMatcher((String) null), StrMatcher.noneMatcher()); StrMatcherTest.assertStrMatcherImpl("CharMatcher", StrMatcher.charSetMatcher("a")); } @Test void testCommaMatcher() { final StrMatcher matcher = StrMatcher.commaMatcher(); assertSame(StrMatcher.commaMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 0)); assertEquals(1, matcher.isMatch(BUFFER1, 1)); assertEquals(0, matcher.isMatch(BUFFER1, 2)); } @Test void testDoubleQuoteMatcher() { final StrMatcher matcher = StrMatcher.doubleQuoteMatcher(); assertSame(StrMatcher.doubleQuoteMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 11)); assertEquals(1, matcher.isMatch(BUFFER1, 12)); } @Test void testMatcherIndices() { // remember that the API contract is tight for the isMatch() method // all the onus is on the caller, so invalid inputs are not // the concern of StrMatcher, and are not bugs final StrMatcher matcher = StrMatcher.stringMatcher("bc"); assertEquals(2, matcher.isMatch(BUFFER2, 1, 1, BUFFER2.length)); assertEquals(2, matcher.isMatch(BUFFER2, 1, 0, 3)); assertEquals(0, matcher.isMatch(BUFFER2, 1, 0, 2)); } @Test void testNoneMatcher() { final StrMatcher matcher = StrMatcher.noneMatcher(); assertSame(StrMatcher.noneMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 0)); assertEquals(0, matcher.isMatch(BUFFER1, 1)); assertEquals(0, matcher.isMatch(BUFFER1, 2)); assertEquals(0, matcher.isMatch(BUFFER1, 3)); assertEquals(0, matcher.isMatch(BUFFER1, 4)); assertEquals(0, matcher.isMatch(BUFFER1, 5)); assertEquals(0, matcher.isMatch(BUFFER1, 6)); assertEquals(0, matcher.isMatch(BUFFER1, 7)); assertEquals(0, matcher.isMatch(BUFFER1, 8)); assertEquals(0, matcher.isMatch(BUFFER1, 9)); assertEquals(0, matcher.isMatch(BUFFER1, 10)); assertEquals(0, matcher.isMatch(BUFFER1, 11)); assertEquals(0, matcher.isMatch(BUFFER1, 12)); } @Test void testQuoteMatcher() { final StrMatcher matcher = StrMatcher.quoteMatcher(); assertSame(StrMatcher.quoteMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 10)); assertEquals(1, matcher.isMatch(BUFFER1, 11)); assertEquals(1, matcher.isMatch(BUFFER1, 12)); } @Test void testSingleQuoteMatcher() { final StrMatcher matcher = StrMatcher.singleQuoteMatcher(); assertSame(StrMatcher.singleQuoteMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 10)); assertEquals(1, matcher.isMatch(BUFFER1, 11)); assertEquals(0, matcher.isMatch(BUFFER1, 12)); } @Test void testSpaceMatcher() { final StrMatcher matcher = StrMatcher.spaceMatcher(); assertSame(StrMatcher.spaceMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 4)); assertEquals(1, matcher.isMatch(BUFFER1, 5)); assertEquals(0, matcher.isMatch(BUFFER1, 6)); } @Test void testSplitMatcher() { final StrMatcher matcher = StrMatcher.splitMatcher(); assertSame(StrMatcher.splitMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 2)); assertEquals(1, matcher.isMatch(BUFFER1, 3)); assertEquals(0, matcher.isMatch(BUFFER1, 4)); assertEquals(1, matcher.isMatch(BUFFER1, 5)); assertEquals(0, matcher.isMatch(BUFFER1, 6)); assertEquals(1, matcher.isMatch(BUFFER1, 7)); assertEquals(1, matcher.isMatch(BUFFER1, 8)); assertEquals(1, matcher.isMatch(BUFFER1, 9)); assertEquals(0, matcher.isMatch(BUFFER1, 10)); } @Test void testStringMatcher_String() { final StrMatcher matcher = StrMatcher.stringMatcher("bc"); assertEquals(0, matcher.isMatch(BUFFER2, 0)); assertEquals(2, matcher.isMatch(BUFFER2, 1)); assertEquals(0, matcher.isMatch(BUFFER2, 2)); assertEquals(0, matcher.isMatch(BUFFER2, 3)); assertEquals(0, matcher.isMatch(BUFFER2, 4)); assertEquals(0, matcher.isMatch(BUFFER2, 5)); assertSame(StrMatcher.stringMatcher(""), StrMatcher.noneMatcher()); assertSame(StrMatcher.stringMatcher((String) null), StrMatcher.noneMatcher()); } @Test void testTabMatcher() { final StrMatcher matcher = StrMatcher.tabMatcher(); assertSame(StrMatcher.tabMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 2)); assertEquals(1, matcher.isMatch(BUFFER1, 3)); assertEquals(0, matcher.isMatch(BUFFER1, 4)); } @Test void testTrimMatcher() { final StrMatcher matcher = StrMatcher.trimMatcher(); assertSame(StrMatcher.trimMatcher(), matcher); assertEquals(0, matcher.isMatch(BUFFER1, 2)); assertEquals(1, matcher.isMatch(BUFFER1, 3)); assertEquals(0, matcher.isMatch(BUFFER1, 4)); assertEquals(1, matcher.isMatch(BUFFER1, 5)); assertEquals(0, matcher.isMatch(BUFFER1, 6)); assertEquals(1, matcher.isMatch(BUFFER1, 7)); assertEquals(1, matcher.isMatch(BUFFER1, 8)); assertEquals(1, matcher.isMatch(BUFFER1, 9)); assertEquals(1, matcher.isMatch(BUFFER1, 10)); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/StrSubstitutorTest.java000066400000000000000000000732641511432740600333660ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.lang3.SystemProperties; import org.apache.commons.lang3.mutable.MutableObject; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Test class for {@link StrSubstitutor}. * * @deprecated This class will be removed in 2.0. */ @Deprecated class StrSubstitutorTest { private Map values; private void doTestNoReplace(final String replaceTemplate) { final StrSubstitutor sub = new StrSubstitutor(values); if (replaceTemplate == null) { assertNull(sub.replace((String) null)); assertNull(sub.replace((String) null, 0, 100)); assertNull(sub.replace((char[]) null)); assertNull(sub.replace((char[]) null, 0, 100)); assertNull(sub.replace((StringBuffer) null)); assertNull(sub.replace((StringBuffer) null, 0, 100)); assertNull(sub.replace((StrBuilder) null)); assertNull(sub.replace((StrBuilder) null, 0, 100)); assertNull(sub.replace((Object) null)); assertFalse(sub.replaceIn((StringBuffer) null)); assertFalse(sub.replaceIn((StringBuffer) null, 0, 100)); assertFalse(sub.replaceIn((StrBuilder) null)); assertFalse(sub.replaceIn((StrBuilder) null, 0, 100)); } else { assertEquals(replaceTemplate, sub.replace(replaceTemplate)); final StrBuilder bld = new StrBuilder(replaceTemplate); assertFalse(sub.replaceIn(bld)); assertEquals(replaceTemplate, bld.toString()); } } private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) { final StrSubstitutor sub = new StrSubstitutor(values); doTestReplace(sub, expectedResult, replaceTemplate, substring); } private void doTestReplace(final StrSubstitutor sub, final String expectedResult, final String replaceTemplate, final boolean substring) { final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1); // replace using String assertEquals(expectedResult, sub.replace(replaceTemplate)); if (substring) { assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2)); } // replace using char[] final char[] chars = replaceTemplate.toCharArray(); assertEquals(expectedResult, sub.replace(chars)); if (substring) { assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2)); } // replace using StringBuffer StringBuffer buf = new StringBuffer(replaceTemplate); assertEquals(expectedResult, sub.replace(buf)); if (substring) { assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2)); } // replace using StringBuilder StringBuilder builder = new StringBuilder(replaceTemplate); assertEquals(expectedResult, sub.replace(builder)); if (substring) { assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2)); } // replace using StrBuilder StrBuilder bld = new StrBuilder(replaceTemplate); assertEquals(expectedResult, sub.replace(bld)); if (substring) { assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2)); } // replace using object final MutableObject obj = new MutableObject<>(replaceTemplate); // toString returns template assertEquals(expectedResult, sub.replace(obj)); // replace in StringBuffer buf = new StringBuffer(replaceTemplate); assertTrue(sub.replaceIn(buf)); assertEquals(expectedResult, buf.toString()); if (substring) { buf = new StringBuffer(replaceTemplate); assertTrue(sub.replaceIn(buf, 1, buf.length() - 2)); assertEquals(expectedResult, buf.toString()); // expect full result as remainder is untouched } // replace in StringBuilder builder = new StringBuilder(replaceTemplate); assertTrue(sub.replaceIn(builder)); assertEquals(expectedResult, builder.toString()); if (substring) { builder = new StringBuilder(replaceTemplate); assertTrue(sub.replaceIn(builder, 1, builder.length() - 2)); assertEquals(expectedResult, builder.toString()); // expect full result as remainder is untouched } // replace in StrBuilder bld = new StrBuilder(replaceTemplate); assertTrue(sub.replaceIn(bld)); assertEquals(expectedResult, bld.toString()); if (substring) { bld = new StrBuilder(replaceTemplate); assertTrue(sub.replaceIn(bld, 1, bld.length() - 2)); assertEquals(expectedResult, bld.toString()); // expect full result as remainder is untouched } } @BeforeEach public void setUp() throws Exception { values = new HashMap<>(); values.put("animal", "quick brown fox"); values.put("target", "lazy dog"); } @AfterEach public void tearDown() throws Exception { values = null; } /** * Tests constructor. */ @Test void testConstructorMapFull() { final Map map = new HashMap<>(); map.put("name", "commons"); StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!'); assertEquals("Hi < commons", sub.replace("Hi !< ")); sub = new StrSubstitutor(map, "<", ">", '!', "||"); assertEquals("Hi < commons", sub.replace("Hi !< ")); } /** * Tests constructor. */ @Test void testConstructorMapPrefixSuffix() { final Map map = new HashMap<>(); map.put("name", "commons"); final StrSubstitutor sub = new StrSubstitutor(map, "<", ">"); assertEquals("Hi < commons", sub.replace("Hi $< ")); } /** * Tests constructor. */ @Test void testConstructorNoArgs() { final StrSubstitutor sub = new StrSubstitutor(); assertEquals("Hi ${name}", sub.replace("Hi ${name}")); } @Test void testCreatesStrSubstitutorTakingStrLookupAndCallsReplaceTakingTwoAndThreeInts() { final Map map = new HashMap<>(); final StrLookup strLookupMapStrLookup = StrLookup.mapLookup(map); final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookupMapStrLookup); assertNull(strSubstitutor.replace((CharSequence) null, 0, 0)); assertEquals('$', strSubstitutor.getEscapeChar()); } /** * Tests a cyclic replace operation. * The cycle should be detected and cause an exception to be thrown. */ @Test void testCyclicReplacement() { final Map map = new HashMap<>(); map.put("animal", "${critter}"); map.put("target", "${pet}"); map.put("pet", "${petCharacteristic} dog"); map.put("petCharacteristic", "lazy"); map.put("critter", "${critterSpeed} ${critterColor} ${critterType}"); map.put("critterSpeed", "quick"); map.put("critterColor", "brown"); map.put("critterType", "${animal}"); final StrSubstitutor sub = new StrSubstitutor(map); assertThrows(IllegalStateException.class, () -> sub.replace("The ${animal} jumps over the ${target}.")); // also check even when default value is set. map.put("critterType", "${animal:-fox}"); assertThrows(IllegalStateException.class, () -> new StrSubstitutor(map).replace("The ${animal} jumps over the ${target}.")); } @Test void testDefaultValueDelimiters() { final Map map = new HashMap<>(); map.put("animal", "fox"); map.put("target", "dog"); StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$'); assertEquals("The fox jumps over the lazy dog. 1234567890.", sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number:-1234567890}.")); sub = new StrSubstitutor(map, "${", "}", '$', "?:"); assertEquals("The fox jumps over the lazy dog. 1234567890.", sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number?:1234567890}.")); sub = new StrSubstitutor(map, "${", "}", '$', "||"); assertEquals("The fox jumps over the lazy dog. 1234567890.", sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number||1234567890}.")); sub = new StrSubstitutor(map, "${", "}", '$', "!"); assertEquals("The fox jumps over the lazy dog. 1234567890.", sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}.")); sub = new StrSubstitutor(map, "${", "}", '$', ""); sub.setValueDelimiterMatcher(null); assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.", sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}.")); sub = new StrSubstitutor(map, "${", "}", '$'); sub.setValueDelimiterMatcher(null); assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.", sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}.")); } @Test void testDisableSubstitutionInValues() { final StrSubstitutor sub = new StrSubstitutor(values); sub.setDisableSubstitutionInValues(true); values.put("animal", "${critter}"); values.put("target", "${pet}"); values.put("pet", "${petCharacteristic} dog"); values.put("petCharacteristic", "lazy"); values.put("critter", "${critterSpeed} ${critterColor} ${critterType}"); values.put("critterSpeed", "quick"); values.put("critterColor", "brown"); values.put("critterType", "fox"); doTestReplace(sub, "The ${critter} jumps over the ${pet}.", "The ${animal} jumps over the ${target}.", true); } /** * Tests get set. */ @Test void testGetSetEscape() { final StrSubstitutor sub = new StrSubstitutor(); assertEquals('$', sub.getEscapeChar()); sub.setEscapeChar('<'); assertEquals('<', sub.getEscapeChar()); } /** * Tests get set. */ @Test void testGetSetPrefix() { final StrSubstitutor sub = new StrSubstitutor(); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); sub.setVariablePrefix('<'); StrMatcherTest.assertStrMatcherPrefixImpl("CharMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); sub.setVariablePrefix("<<"); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefix((String) null)); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); final StrMatcher matcher = StrMatcher.commaMatcher(); sub.setVariablePrefixMatcher(matcher); assertSame(matcher, sub.getVariablePrefixMatcher()); assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefixMatcher((StrMatcher) null)); assertSame(matcher, sub.getVariablePrefixMatcher()); } /** * Tests get set. */ @Test void testGetSetSuffix() { final StrSubstitutor sub = new StrSubstitutor(); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); sub.setVariableSuffix('<'); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("CharMatcher", sub); sub.setVariableSuffix("<<"); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffix((String) null)); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); final StrMatcher matcher = StrMatcher.commaMatcher(); sub.setVariableSuffixMatcher(matcher); assertSame(matcher, sub.getVariableSuffixMatcher()); assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffixMatcher((StrMatcher) null)); assertSame(matcher, sub.getVariableSuffixMatcher()); } /** * Tests get set. */ @Test void testGetSetValueDelimiter() { final StrSubstitutor sub = new StrSubstitutor(); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); sub.setValueDelimiter(':'); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); sub.setValueDelimiter("||"); StrMatcherTest.assertStrMatcherPrefixImpl("StringMatcher", sub); StrMatcherTest.assertStrMatcherSuffixImpl("StringMatcher", sub); sub.setValueDelimiter((String) null); assertNull(sub.getValueDelimiterMatcher()); final StrMatcher matcher = StrMatcher.commaMatcher(); sub.setValueDelimiterMatcher(matcher); assertSame(matcher, sub.getValueDelimiterMatcher()); sub.setValueDelimiterMatcher((StrMatcher) null); assertNull(sub.getValueDelimiterMatcher()); } /** * Test for LANG-1055: StrSubstitutor.replaceSystemProperties does not work consistently */ @Test void testLANG1055() { System.setProperty("test_key", "test_value"); final String expected = StrSubstitutor.replace("test_key=${test_key}", System.getProperties()); final String actual = StrSubstitutor.replaceSystemProperties("test_key=${test_key}"); assertEquals(expected, actual); } /** * Tests adjacent keys. */ @Test void testReplaceAdjacentAtEnd() { values.put("code", "GBP"); values.put("amount", "12.50"); final StrSubstitutor sub = new StrSubstitutor(values); assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}")); } /** * Tests adjacent keys. */ @Test void testReplaceAdjacentAtStart() { values.put("code", "GBP"); values.put("amount", "12.50"); final StrSubstitutor sub = new StrSubstitutor(values); assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged")); } /** * Tests key replace changing map after initialization (not recommended). */ @Test void testReplaceChangedMap() { final StrSubstitutor sub = new StrSubstitutor(values); values.put("target", "moon"); assertEquals("The quick brown fox jumps over the moon.", sub.replace("The ${animal} jumps over the ${target}.")); } /** * Tests complex escaping. */ @Test void testReplaceComplexEscaping() { doTestReplace("The ${quick brown fox} jumps over the lazy dog.", "The $${${animal}} jumps over the ${target}.", true); doTestReplace("The ${quick brown fox} jumps over the lazy dog. ${1234567890}.", "The $${${animal}} jumps over the ${target}. $${${undefined.number:-1234567890}}.", true); } /** * Tests replace with null. */ @Test void testReplaceEmpty() { doTestNoReplace(""); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeys() { doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true); doTestReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true); } /** * Tests escaping. */ @Test void testReplaceEscaping() { doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true); } /** * Tests when no incomplete prefix. */ @Test void testReplaceIncompletePrefix() { doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true); } @Test void testReplaceInTakingStringBufferWithNonNull() { final StrSubstitutor strSubstitutor = new StrSubstitutor(new HashMap<>(), "WV@i#y?N*[", "WV@i#y?N*[", '*'); assertFalse(strSubstitutor.isPreserveEscapes()); assertFalse(strSubstitutor.replaceIn(new StringBuffer("WV@i#y?N*["))); assertEquals('*', strSubstitutor.getEscapeChar()); } @Test void testReplaceInTakingStringBuilderWithNonNull() { final StrLookup strLookup = StrLookup.systemPropertiesLookup(); final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookup, "b map = new HashMap<>(); final StrSubstitutor strSubstitutor = new StrSubstitutor(map, "", "", 'T', "K+<'f"); assertFalse(strSubstitutor.replaceIn((StringBuilder) null)); } @Test void testReplaceInTakingTwoAndThreeIntsReturningFalse() { final Map hashMap = new HashMap<>(); final StrLookup strLookupMapStrLookup = StrLookup.mapLookup(hashMap); final StrMatcher strMatcher = StrMatcher.tabMatcher(); final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookupMapStrLookup, strMatcher, strMatcher, 'b', strMatcher); assertFalse(strSubstitutor.replaceIn((StringBuilder) null, 1315, -1369)); assertEquals('b', strSubstitutor.getEscapeChar()); assertFalse(strSubstitutor.isPreserveEscapes()); } /** * Tests whether a variable can be replaced in a variable name. */ @Test void testReplaceInVariable() { values.put("animal.1", "fox"); values.put("animal.2", "mouse"); values.put("species", "2"); final StrSubstitutor sub = new StrSubstitutor(values); sub.setEnableSubstitutionInVariables(true); assertEquals( "The mouse jumps over the lazy dog.", sub.replace("The ${animal.${species}} jumps over the ${target}.")); values.put("species", "1"); assertEquals( "The fox jumps over the lazy dog.", sub.replace("The ${animal.${species}} jumps over the ${target}.")); assertEquals( "The fox jumps over the lazy dog.", sub.replace("The ${unknown.animal.${unknown.species:-1}:-fox} " + "jumps over the ${unknow.target:-lazy dog}.")); } /** * Tests whether substitution in variable names is disabled per default. */ @Test void testReplaceInVariableDisabled() { values.put("animal.1", "fox"); values.put("animal.2", "mouse"); values.put("species", "2"); final StrSubstitutor sub = new StrSubstitutor(values); assertEquals( "The ${animal.${species}} jumps over the lazy dog.", sub.replace("The ${animal.${species}} jumps over the ${target}.")); assertEquals( "The ${animal.${species:-1}} jumps over the lazy dog.", sub.replace("The ${animal.${species:-1}} jumps over the ${target}.")); } /** * Tests complex and recursive substitution in variable names. */ @Test void testReplaceInVariableRecursive() { values.put("animal.2", "brown fox"); values.put("animal.1", "white mouse"); values.put("color", "white"); values.put("species.white", "1"); values.put("species.brown", "2"); final StrSubstitutor sub = new StrSubstitutor(values); sub.setEnableSubstitutionInVariables(true); assertEquals( "The white mouse jumps over the lazy dog.", sub.replace("The ${animal.${species.${color}}} jumps over the ${target}.")); assertEquals( "The brown fox jumps over the lazy dog.", sub.replace("The ${animal.${species.${unknownColor:-brown}}} jumps over the ${target}.")); } /** * Tests when no prefix or suffix. */ @Test void testReplaceNoPrefixNoSuffix() { doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true); } /** * Tests when suffix but no prefix. */ @Test void testReplaceNoPrefixSuffix() { doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true); } /** * Tests replace with no variables. */ @Test void testReplaceNoVariables() { doTestNoReplace("The balloon arrived."); } /** * Tests replace with null. */ @Test void testReplaceNull() { doTestNoReplace(null); } /** * Tests simple key replace. */ @Test void testReplacePartialString_noReplace() { final StrSubstitutor sub = new StrSubstitutor(); assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15)); } /** * Tests when prefix but no suffix. */ @Test void testReplacePrefixNoSuffix() { doTestReplace("The ${animal jumps over the ${target} lazy dog.", "The ${animal jumps over the ${target} ${target}.", true); } /** * Tests simple recursive replace. */ @Test void testReplaceRecursive() { values.put("animal", "${critter}"); values.put("target", "${pet}"); values.put("pet", "${petCharacteristic} dog"); values.put("petCharacteristic", "lazy"); values.put("critter", "${critterSpeed} ${critterColor} ${critterType}"); values.put("critterSpeed", "quick"); values.put("critterColor", "brown"); values.put("critterType", "fox"); doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true); values.put("pet", "${petCharacteristicUnknown:-lazy} dog"); doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true); } /** * Tests simple key replace. */ @Test void testReplaceSimple() { doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true); } /** * Tests simple key replace. */ @Test void testReplaceSolo() { doTestReplace("quick brown fox", "${animal}", false); } /** * Tests escaping. */ @Test void testReplaceSoloEscaping() { doTestReplace("${animal}", "$${animal}", false); } @Test void testReplaceTakingCharSequenceReturningNull() { final StrSubstitutor strSubstitutor = new StrSubstitutor((StrLookup) null); assertNull(strSubstitutor.replace((CharSequence) null)); assertFalse(strSubstitutor.isPreserveEscapes()); assertEquals('$', strSubstitutor.getEscapeChar()); } @Test void testReplaceTakingThreeArgumentsThrowsNullPointerException() { assertThrows(NullPointerException.class, () -> StrSubstitutor.replace(null, (Properties) null)); } /** * Tests replace creates output same as input. */ @Test void testReplaceToIdentical() { values.put("animal", "$${${thing}}"); values.put("thing", "animal"); doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownKey() { doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true); doTestReplace("The ${person} jumps over the lazy dog. 1234567890.", "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true); } /** * Tests interpolation with weird boundary patterns. */ @Test void testReplaceWeirdPattens() { doTestNoReplace(""); doTestNoReplace("${}"); doTestNoReplace("${ }"); doTestNoReplace("${\t}"); doTestNoReplace("${\n}"); doTestNoReplace("${\b}"); doTestNoReplace("${"); doTestNoReplace("$}"); doTestNoReplace("}"); doTestNoReplace("${}$"); doTestNoReplace("${${"); doTestNoReplace("${${}}"); doTestNoReplace("${$${}}"); doTestNoReplace("${$$${}}"); doTestNoReplace("${$$${$}}"); doTestNoReplace("${${}}"); doTestNoReplace("${${ }}"); } /** * Tests protected. */ @Test void testResolveVariable() { final StrBuilder builder = new StrBuilder("Hi ${name}!"); final Map map = new HashMap<>(); map.put("name", "commons"); final StrSubstitutor sub = new StrSubstitutor(map) { @Override protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) { assertEquals("name", variableName); assertSame(builder, buf); assertEquals(3, startPos); assertEquals(10, endPos); return "jakarta"; } }; sub.replaceIn(builder); assertEquals("Hi jakarta!", builder.toString()); } @Test void testSamePrefixAndSuffix() { final Map map = new HashMap<>(); map.put("greeting", "Hello"); map.put(" there ", "XXX"); map.put("name", "commons"); assertEquals("Hi commons!", StrSubstitutor.replace("Hi @name@!", map, "@", "@")); assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@")); } /** * Tests static. */ @Test void testStaticReplace() { final Map map = new HashMap<>(); map.put("name", "commons"); assertEquals("Hi commons!", StrSubstitutor.replace("Hi ${name}!", map)); } /** * Tests static. */ @Test void testStaticReplacePrefixSuffix() { final Map map = new HashMap<>(); map.put("name", "commons"); assertEquals("Hi commons!", StrSubstitutor.replace("Hi !", map, "<", ">")); } /** * Tests interpolation with system properties. */ @Test void testStaticReplaceSystemProperties() { final StrBuilder buf = new StrBuilder(); buf.append("Hi ").append(SystemProperties.getUserName()); buf.append(", you are working with "); buf.append(SystemProperties.getOsName()); buf.append(", your home directory is "); buf.append(SystemProperties.getUserHome()).append('.'); assertEquals(buf.toString(), StrSubstitutor.replaceSystemProperties("Hi ${user.name}, you are " + "working with ${os.name}, your home " + "directory is ${user.home}.")); } /** * Test the replace of a properties object */ @Test void testSubstituteDefaultProperties() { final String org = "${doesnotwork}"; System.setProperty("doesnotwork", "It works!"); // create a new Properties object with the System.getProperties as default final Properties props = new Properties(System.getProperties()); assertEquals("It works!", StrSubstitutor.replace(org, props)); } @Test void testSubstitutePreserveEscape() { final String org = "${not-escaped} $${escaped}"; final Map map = new HashMap<>(); map.put("not-escaped", "value"); final StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$'); assertFalse(sub.isPreserveEscapes()); assertEquals("value ${escaped}", sub.replace(org)); sub.setPreserveEscapes(true); assertTrue(sub.isPreserveEscapes()); assertEquals("value $${escaped}", sub.replace(org)); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/StrTokenizerTest.java000066400000000000000000000751501511432740600327650ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.Test; /** * Unit test for {@link StrTokenizer}. * * @deprecated This class will be removed in 2.0. */ @Deprecated class StrTokenizerTest { private static final String CSV_SIMPLE_FIXTURE = "A,b,c"; private static final String TSV_SIMPLE_FIXTURE = "A\tb\tc"; private void checkClone(final StrTokenizer tokenizer) { assertNotSame(StrTokenizer.getCSVInstance(), tokenizer); assertNotSame(StrTokenizer.getTSVInstance(), tokenizer); } @Test void test1() { final String input = "a;b;c;\"d;\"\"e\";f; ; ; "; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d;\"e", "f", "", "", ""}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test2() { final String input = "a;b;c ;\"d;\"\"e\";f; ; ;"; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StrMatcher.noneMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c ", "d;\"e", "f", " ", " ", ""}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test3() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StrMatcher.noneMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", " c", "d;\"e", "f", " ", " ", ""}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test4() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d;\"e", "f"}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test5() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d;\"e", "f", null, null, null}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test6() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); // tok.setTreatingEmptyAsNull(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", " c", "d;\"e", "f", null, null, null}; int nextCount = 0; while (tok.hasNext()) { tok.next(); nextCount++; } int prevCount = 0; while (tok.hasPrevious()) { tok.previous(); prevCount++; } assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); assertEquals(nextCount, expected.length, "could not cycle through entire token list using the 'hasNext' and 'next' methods"); assertEquals(prevCount, expected.length, "could not cycle through entire token list using the 'hasPrevious' and 'previous' methods"); } @Test void test7() { final String input = "a b c \"d e\" f "; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterMatcher(StrMatcher.spaceMatcher()); tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher()); tok.setIgnoredMatcher(StrMatcher.noneMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "", "", "b", "c", "d e", "f", ""}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test8() { final String input = "a b c \"d e\" f "; final StrTokenizer tok = new StrTokenizer(input); tok.setDelimiterMatcher(StrMatcher.spaceMatcher()); tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher()); tok.setIgnoredMatcher(StrMatcher.noneMatcher()); tok.setIgnoreEmptyTokens(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d e", "f"}; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void testBasic1() { final String input = "a b c"; final StrTokenizer tok = new StrTokenizer(input); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic2() { final String input = "a \nb\fc"; final StrTokenizer tok = new StrTokenizer(input); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic3() { final String input = "a \nb\u0001\fc"; final StrTokenizer tok = new StrTokenizer(input); assertEquals("a", tok.next()); assertEquals("b\u0001", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic4() { final String input = "a \"b\" c"; final StrTokenizer tok = new StrTokenizer(input); assertEquals("a", tok.next()); assertEquals("\"b\"", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic5() { final String input = "a:b':c"; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); assertEquals("a", tok.next()); assertEquals("b'", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicDelim1() { final String input = "a:b:c"; final StrTokenizer tok = new StrTokenizer(input, ':'); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicDelim2() { final String input = "a:b:c"; final StrTokenizer tok = new StrTokenizer(input, ','); assertEquals("a:b:c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicEmpty1() { final String input = "a b c"; final StrTokenizer tok = new StrTokenizer(input); tok.setIgnoreEmptyTokens(false); assertEquals("a", tok.next()); assertEquals("", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicEmpty2() { final String input = "a b c"; final StrTokenizer tok = new StrTokenizer(input); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertNull(tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed1() { final String input = "a: bIGNOREc : "; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE")); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bc", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed2() { final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE "; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE")); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bc", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed3() { final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE "; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE")); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals(" bc ", tok.next()); assertEquals(" ", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed4() { final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE "; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE")); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bIGNOREcd", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted1() { final String input = "a 'b' c"; final StrTokenizer tok = new StrTokenizer(input, ' ', '\''); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted2() { final String input = "a:'b':"; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted3() { final String input = "a:'b''c'"; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b'c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted4() { final String input = "a: 'b' 'c' :d"; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b c", tok.next()); assertEquals("d", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted5() { final String input = "a: 'b'x'c' :d"; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bxc", tok.next()); assertEquals("d", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted6() { final String input = "a:'b'\"c':d"; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setQuoteMatcher(StrMatcher.quoteMatcher()); assertEquals("a", tok.next()); assertEquals("b\"c:d", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted7() { final String input = "a:\"There's a reason here\":b"; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setQuoteMatcher(StrMatcher.quoteMatcher()); assertEquals("a", tok.next()); assertEquals("There's a reason here", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuotedTrimmed1() { final String input = "a: 'b' :"; final StrTokenizer tok = new StrTokenizer(input, ':', '\''); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicTrimmed1() { final String input = "a: b : "; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setTrimmerMatcher(StrMatcher.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicTrimmed2() { final String input = "a: b :"; final StrTokenizer tok = new StrTokenizer(input, ':'); tok.setTrimmerMatcher(StrMatcher.stringMatcher(" ")); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testChaining() { final StrTokenizer tok = new StrTokenizer(); assertEquals(tok, tok.reset()); assertEquals(tok, tok.reset("")); assertEquals(tok, tok.reset(ArrayUtils.EMPTY_CHAR_ARRAY)); assertEquals(tok, tok.setDelimiterChar(' ')); assertEquals(tok, tok.setDelimiterString(" ")); assertEquals(tok, tok.setDelimiterMatcher(null)); assertEquals(tok, tok.setQuoteChar(' ')); assertEquals(tok, tok.setQuoteMatcher(null)); assertEquals(tok, tok.setIgnoredChar(' ')); assertEquals(tok, tok.setIgnoredMatcher(null)); assertEquals(tok, tok.setTrimmerMatcher(null)); assertEquals(tok, tok.setEmptyTokenAsNull(false)); assertEquals(tok, tok.setIgnoreEmptyTokens(false)); } /** * Tests that the {@link StrTokenizer#clone()} clone method catches * {@link CloneNotSupportedException} and returns {@code null}. */ @Test void testCloneNotSupportedException() { final Object notCloned = new StrTokenizer() { @Override Object cloneReset() throws CloneNotSupportedException { throw new CloneNotSupportedException("test"); } }.clone(); assertNull(notCloned); } @Test void testCloneNull() { final StrTokenizer tokenizer = new StrTokenizer((char[]) null); // Start sanity check assertNull(tokenizer.nextToken()); tokenizer.reset(); assertNull(tokenizer.nextToken()); // End sanity check final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone(); tokenizer.reset(); assertNull(tokenizer.nextToken()); assertNull(clonedTokenizer.nextToken()); } @Test void testCloneReset() { final char[] input = {'a'}; final StrTokenizer tokenizer = new StrTokenizer(input); // Start sanity check assertEquals("a", tokenizer.nextToken()); tokenizer.reset(input); assertEquals("a", tokenizer.nextToken()); // End sanity check final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone(); input[0] = 'b'; tokenizer.reset(input); assertEquals("b", tokenizer.nextToken()); assertEquals("a", clonedTokenizer.nextToken()); } @Test void testConstructor_charArray() { StrTokenizer tok = new StrTokenizer("a b".toCharArray()); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY); assertFalse(tok.hasNext()); tok = new StrTokenizer((char[]) null); assertFalse(tok.hasNext()); } @Test void testConstructor_charArray_char() { StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' '); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' '); assertFalse(tok.hasNext()); tok = new StrTokenizer((char[]) null, ' '); assertFalse(tok.hasNext()); } @Test void testConstructor_charArray_char_char() { StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ', '"'); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"'); assertFalse(tok.hasNext()); tok = new StrTokenizer((char[]) null, ' ', '"'); assertFalse(tok.hasNext()); } @Test void testConstructor_String() { StrTokenizer tok = new StrTokenizer("a b"); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StrTokenizer(""); assertFalse(tok.hasNext()); tok = new StrTokenizer((String) null); assertFalse(tok.hasNext()); } @Test void testConstructor_String_char() { StrTokenizer tok = new StrTokenizer("a b", ' '); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StrTokenizer("", ' '); assertFalse(tok.hasNext()); tok = new StrTokenizer((String) null, ' '); assertFalse(tok.hasNext()); } @Test void testConstructor_String_char_char() { StrTokenizer tok = new StrTokenizer("a b", ' ', '"'); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StrTokenizer("", ' ', '"'); assertFalse(tok.hasNext()); tok = new StrTokenizer((String) null, ' ', '"'); assertFalse(tok.hasNext()); } private void testCSV(final String data) { testXSVAbc(StrTokenizer.getCSVInstance(data)); testXSVAbc(StrTokenizer.getCSVInstance(data.toCharArray())); } @Test void testCSVEmpty() { testEmpty(StrTokenizer.getCSVInstance()); testEmpty(StrTokenizer.getCSVInstance("")); } @Test void testCSVSimple() { testCSV(CSV_SIMPLE_FIXTURE); } @Test void testCSVSimpleNeedsTrim() { testCSV(" " + CSV_SIMPLE_FIXTURE); testCSV(" \n\t " + CSV_SIMPLE_FIXTURE); testCSV(" \n " + CSV_SIMPLE_FIXTURE + "\n\n\r"); } @Test void testDelimMatcher() { final String input = "a/b\\c"; final StrMatcher delimMatcher = StrMatcher.charSetMatcher(new char[] {'/', '\\'}); final StrTokenizer tok = new StrTokenizer(input, delimMatcher); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testDelimMatcherQuoteMatcher() { final String input = "`a`;`b`;`c`"; final StrMatcher delimMatcher = StrMatcher.charSetMatcher(new char[] {';'}); final StrMatcher quoteMatcher = StrMatcher.charSetMatcher(new char[] {'`'}); final StrTokenizer tok = new StrTokenizer(input, delimMatcher, quoteMatcher); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testDelimString() { final String input = "a##b##c"; final StrTokenizer tok = new StrTokenizer(input, "##"); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } void testEmpty(final StrTokenizer tokenizer) { checkClone(tokenizer); assertFalse(tokenizer.hasNext()); assertFalse(tokenizer.hasPrevious()); assertNull(tokenizer.nextToken()); assertEquals(0, tokenizer.size()); assertThrows(NoSuchElementException.class, tokenizer::next); } @Test void testGetContent() { final String input = "a b c \"d e\" f "; StrTokenizer tok = new StrTokenizer(input); assertEquals(input, tok.getContent()); tok = new StrTokenizer(input.toCharArray()); assertEquals(input, tok.getContent()); tok = new StrTokenizer(); assertNull(tok.getContent()); } @Test void testIteration() { final StrTokenizer tkn = new StrTokenizer("a b c"); assertFalse(tkn.hasPrevious()); assertThrows(NoSuchElementException.class, tkn::previous); assertTrue(tkn.hasNext()); assertEquals("a", tkn.next()); assertThrows(UnsupportedOperationException.class, tkn::remove); assertThrows(UnsupportedOperationException.class, () -> tkn.set("x")); assertThrows(UnsupportedOperationException.class, () -> tkn.add("y")); assertTrue(tkn.hasPrevious()); assertTrue(tkn.hasNext()); assertEquals("b", tkn.next()); assertTrue(tkn.hasPrevious()); assertTrue(tkn.hasNext()); assertEquals("c", tkn.next()); assertTrue(tkn.hasPrevious()); assertFalse(tkn.hasNext()); assertThrows(NoSuchElementException.class, tkn::next); assertTrue(tkn.hasPrevious()); assertFalse(tkn.hasNext()); } @Test void testListArray() { final String input = "a b c"; final StrTokenizer tok = new StrTokenizer(input); final String[] array = tok.getTokenArray(); final List list = tok.getTokenList(); assertEquals(Arrays.asList(array), list); assertEquals(3, list.size()); } @Test void testPreviousTokenAndSetEmptyTokenAsNull() { final StrTokenizer strTokenizer = StrTokenizer.getTSVInstance(" \t\n\r\f"); strTokenizer.setEmptyTokenAsNull(true); assertNull(strTokenizer.previousToken()); } @Test void testReset() { final StrTokenizer tok = new StrTokenizer("a b c"); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); tok.reset(); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testReset_charArray() { final StrTokenizer tok = new StrTokenizer("x x x"); final char[] array = {'a', 'b', 'c'}; tok.reset(array); assertEquals("abc", tok.next()); assertFalse(tok.hasNext()); tok.reset((char[]) null); assertFalse(tok.hasNext()); } @Test void testReset_String() { final StrTokenizer tok = new StrTokenizer("x x x"); tok.reset("d e"); assertEquals("d", tok.next()); assertEquals("e", tok.next()); assertFalse(tok.hasNext()); tok.reset((String) null); assertFalse(tok.hasNext()); } @Test void testStringTokenizerQuoteMatcher() { final char[] chars = {'\'', 'a', 'c', '\'', 'd'}; final StrTokenizer tokens = new StrTokenizer(chars, StrMatcher.commaMatcher(), StrMatcher.quoteMatcher()); assertEquals("acd", tokens.next()); } @Test void testStringTokenizerStringMatcher() { final char[] chars = {'a', 'b', 'c', 'd'}; final StrTokenizer tokens = new StrTokenizer(chars, "bc"); assertEquals("a", tokens.next()); assertEquals("d", tokens.next()); } @Test void testStringTokenizerStrMatcher() { final char[] chars = {'a', ',', 'c'}; final StrTokenizer tokens = new StrTokenizer(chars, StrMatcher.commaMatcher()); assertEquals("a", tokens.next()); assertEquals("c", tokens.next()); } @Test void testTokenizeSubclassInputChange() { final StrTokenizer tkn = new StrTokenizer("a b c d e") { @Override protected List tokenize(final char[] chars, final int offset, final int count) { return super.tokenize("w x y z".toCharArray(), 2, 5); } }; assertEquals("x", tkn.next()); assertEquals("y", tkn.next()); } @Test void testTokenizeSubclassOutputChange() { final StrTokenizer tkn = new StrTokenizer("a b c") { @Override protected List tokenize(final char[] chars, final int offset, final int count) { final List list = super.tokenize(chars, offset, count); Collections.reverse(list); return list; } }; assertEquals("c", tkn.next()); assertEquals("b", tkn.next()); assertEquals("a", tkn.next()); } @Test void testToString() { final StrTokenizer tkn = new StrTokenizer("a b c d e"); assertEquals("StrTokenizer[not tokenized yet]", tkn.toString()); tkn.next(); assertEquals("StrTokenizer[a, b, c, d, e]", tkn.toString()); } @Test void testTSV() { testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE)); testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray())); } @Test void testTSVEmpty() { testEmpty(StrTokenizer.getTSVInstance()); testEmpty(StrTokenizer.getTSVInstance("")); } void testXSVAbc(final StrTokenizer tokenizer) { checkClone(tokenizer); assertEquals(-1, tokenizer.previousIndex()); assertEquals(0, tokenizer.nextIndex()); assertNull(tokenizer.previousToken()); assertEquals("A", tokenizer.nextToken()); assertEquals(1, tokenizer.nextIndex()); assertEquals("b", tokenizer.nextToken()); assertEquals(2, tokenizer.nextIndex()); assertEquals("c", tokenizer.nextToken()); assertEquals(3, tokenizer.nextIndex()); assertNull(tokenizer.nextToken()); assertEquals(3, tokenizer.nextIndex()); assertEquals("c", tokenizer.previousToken()); assertEquals(2, tokenizer.nextIndex()); assertEquals("b", tokenizer.previousToken()); assertEquals(1, tokenizer.nextIndex()); assertEquals("A", tokenizer.previousToken()); assertEquals(0, tokenizer.nextIndex()); assertNull(tokenizer.previousToken()); assertEquals(0, tokenizer.nextIndex()); assertEquals(-1, tokenizer.previousIndex()); assertEquals(3, tokenizer.size()); } } StringEscapeUtilsTest.java000066400000000000000000000646651511432740600336640ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.apache.commons.text.StringEscapeUtils.escapeXSI; import static org.apache.commons.text.StringEscapeUtils.unescapeXSI; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.io.StringWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import org.junit.jupiter.api.Test; /** * Tests {@link StringEscapeUtils}. * *

* This code has been adapted from Apache Commons Lang 3.5. *

*/ class StringEscapeUtilsTest { private static final String FOO = "foo"; private static final String[][] HTML_ESCAPES = { {"no escaping", "plain text", "plain text"}, {"no escaping", "plain text", "plain text"}, {"empty string", "", ""}, {"null", null, null}, {"ampersand", "bread & butter", "bread & butter"}, {"quotes", ""bread" & butter", "\"bread\" & butter"}, {"final character only", "greater than >", "greater than >"}, {"first character only", "< less than", "< less than"}, {"apostrophe", "Huntington's chorea", "Huntington's chorea"}, {"languages", "English,Français,\u65E5\u672C\u8A9E (nihongo)", "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"}, {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"}, }; private void assertEscapeJava(final String escaped, final String original) throws IOException { assertEscapeJava(escaped, original, null); } private void assertEscapeJava(final String expected, final String original, String message) throws IOException { final String converted = StringEscapeUtils.escapeJava(original); message = "escapeJava(String) failed" + (message == null ? "" : ": " + message); assertEquals(expected, converted, message); final StringWriter writer = new StringWriter(); StringEscapeUtils.ESCAPE_JAVA.translate(original, writer); assertEquals(expected, writer.toString()); } private void assertUnescapeJava(final String unescaped, final String original) throws IOException { assertUnescapeJava(unescaped, original, null); } private void assertUnescapeJava(final String unescaped, final String original, final String message) throws IOException { final String actual = StringEscapeUtils.unescapeJava(original); assertEquals(unescaped, actual, "unescape(String) failed" + (message == null ? "" : ": " + message) + ": expected '" + StringEscapeUtils.escapeJava(unescaped) // we escape this so we can see it in the error message + "' actual '" + StringEscapeUtils.escapeJava(actual) + "'"); final StringWriter writer = new StringWriter(); StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer); assertEquals(unescaped, writer.toString()); } private void checkCsvEscapeWriter(final String expected, final String value) throws IOException { final StringWriter writer = new StringWriter(); StringEscapeUtils.ESCAPE_CSV.translate(value, writer); assertEquals(expected, writer.toString()); } private void checkCsvUnescapeWriter(final String expected, final String value) throws IOException { final StringWriter writer = new StringWriter(); StringEscapeUtils.UNESCAPE_CSV.translate(value, writer); assertEquals(expected, writer.toString()); } @Test void testBuilder() { final String result = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_XML10).escape("<").append(">").toString(); assertEquals("<>", result); } @Test void testConstructor() { assertNotNull(new StringEscapeUtils()); final Constructor[] cons = StringEscapeUtils.class.getDeclaredConstructors(); assertEquals(1, cons.length); assertTrue(Modifier.isPublic(cons[0].getModifiers())); assertTrue(Modifier.isPublic(StringEscapeUtils.class.getModifiers())); assertFalse(Modifier.isFinal(StringEscapeUtils.class.getModifiers())); } // HTML and XML @Test void testDeleteCharacter() { final String deleteString = "Delete: \u007F"; assertEquals("Delete: \\u007F", StringEscapeUtils.escapeJson(deleteString)); } @Test void testEscapeCsvString() { assertEquals("foo.bar", StringEscapeUtils.escapeCsv("foo.bar")); assertEquals("\"foo,bar\"", StringEscapeUtils.escapeCsv("foo,bar")); assertEquals("\"foo\nbar\"", StringEscapeUtils.escapeCsv("foo\nbar")); assertEquals("\"foo\rbar\"", StringEscapeUtils.escapeCsv("foo\rbar")); assertEquals("\"foo\"\"bar\"", StringEscapeUtils.escapeCsv("foo\"bar")); assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.escapeCsv("foo\uD84C\uDFB4bar")); assertEquals("", StringEscapeUtils.escapeCsv("")); assertNull(StringEscapeUtils.escapeCsv(null)); } @Test void testEscapeCsvWriter() throws IOException { checkCsvEscapeWriter("foo.bar", "foo.bar"); checkCsvEscapeWriter("\"foo,bar\"", "foo,bar"); checkCsvEscapeWriter("\"foo\nbar\"", "foo\nbar"); checkCsvEscapeWriter("\"foo\rbar\"", "foo\rbar"); checkCsvEscapeWriter("\"foo\"\"bar\"", "foo\"bar"); checkCsvEscapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar"); checkCsvEscapeWriter("", null); checkCsvEscapeWriter("", ""); } @Test void testEscapeEcmaScript() { assertNull(StringEscapeUtils.escapeEcmaScript(null)); try { StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } try { StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\"")); assertEquals("document.getElementById(\\\"test\\\").value = \\'';")); } /** * Tests https://issues.apache.org/jira/browse/LANG-339 */ @Test void testEscapeHiragana() { // Some random Japanese Unicode characters final String original = "\u304B\u304C\u3068"; final String escaped = StringEscapeUtils.escapeHtml4(original); assertEquals(original, escaped, "Hiragana character Unicode behavior should not be being escaped by escapeHtml4"); final String unescaped = StringEscapeUtils.unescapeHtml4(escaped); assertEquals(escaped, unescaped, "Hiragana character Unicode behavior has changed - expected no unescaping"); } @Test void testEscapeHtml3() { for (final String[] element : HTML_ESCAPES) { final String message = element[0]; final String expected = element[1]; final String original = element[2]; assertEquals(expected, StringEscapeUtils.escapeHtml4(original), message); final StringWriter sw = new StringWriter(); try { StringEscapeUtils.ESCAPE_HTML3.translate(original, sw); } catch (final IOException e) { // expected } final String actual = original == null ? null : sw.toString(); assertEquals(expected, actual, message); } } @Test void testEscapeHtml4() { for (final String[] element : HTML_ESCAPES) { final String message = element[0]; final String expected = element[1]; final String original = element[2]; assertEquals(expected, StringEscapeUtils.escapeHtml4(original), message); final StringWriter sw = new StringWriter(); try { StringEscapeUtils.ESCAPE_HTML4.translate(original, sw); } catch (final IOException e) { // expected } final String actual = original == null ? null : sw.toString(); assertEquals(expected, actual, message); } } /** * Tests // https://issues.apache.org/jira/browse/LANG-480 */ @Test void testEscapeHtmlHighUnicode() { // this is the utf8 representation of the character: // COUNTING ROD UNIT DIGIT THREE // in Unicode // code point: U+1D362 final byte[] data = { (byte) 0xF0, (byte) 0x9D, (byte) 0x8D, (byte) 0xA2 }; final String original = new String(data, StandardCharsets.UTF_8); final String escaped = StringEscapeUtils.escapeHtml4(original); assertEquals(original, escaped, "High Unicode should not have been escaped"); final String unescaped = StringEscapeUtils.unescapeHtml4(escaped); assertEquals(original, unescaped, "High Unicode should have been unchanged"); // TODO: I think this should hold, needs further investigation // String unescapedFromEntity = StringEscapeUtils.unescapeHtml4("𝍢"); // assertEquals("High Unicode should have been unescaped", original, unescapedFromEntity); } @Test void testEscapeHtmlThree() { assertNull(StringEscapeUtils.escapeHtml3(null)); assertEquals("a", StringEscapeUtils.escapeHtml3("a")); assertEquals("<b>a", StringEscapeUtils.escapeHtml3("a")); } @Test void testEscapeHtmlVersions() { assertEquals("Β", StringEscapeUtils.escapeHtml4("\u0392")); assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("Β")); // TODO: refine API for escaping/unescaping specific HTML versions } @Test void testEscapeJava() throws IOException { assertNull(StringEscapeUtils.escapeJava(null)); try { StringEscapeUtils.ESCAPE_JAVA.translate(null, null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } try { StringEscapeUtils.ESCAPE_JAVA.translate("", null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } assertEscapeJava("", "", "empty string"); assertEscapeJava(FOO, FOO); assertEscapeJava("\\t", "\t", "tab"); assertEscapeJava("\\\\", "\\", "backslash"); assertEscapeJava("'", "'", "single quote should not be escaped"); assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r"); assertEscapeJava("\\u1234", "\u1234"); assertEscapeJava("\\u0234", "\u0234"); assertEscapeJava("\\u00EF", "\u00ef"); assertEscapeJava("\\u0001", "\u0001"); assertEscapeJava("\\uABCD", "\uabcd", "Should use capitalized Unicode hex"); assertEscapeJava("He didn't say, \\\"stop!\\\"", "He didn't say, \"stop!\""); assertEscapeJava("This space is non-breaking:\\u00A0", "This space is non-breaking:\u00a0", "non-breaking space"); assertEscapeJava("\\uABCD\\u1234\\u012C", "\uABCD\u1234\u012C"); } /** * Tests https://issues.apache.org/jira/browse/LANG-421 */ @Test void testEscapeJavaWithSlash() { final String input = "String with a slash (/) in it"; final String actual = StringEscapeUtils.escapeJava(input); /* * In 2.4 StringEscapeUtils.escapeJava(String) escapes '/' characters, which are not a valid character to escape in a Java string. */ assertEquals(input, actual); } @Test void testEscapeJson() { assertNull(StringEscapeUtils.escapeJson(null)); try { StringEscapeUtils.ESCAPE_JSON.translate(null, null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } try { StringEscapeUtils.ESCAPE_JSON.translate("", null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } assertEquals("He didn't say, \\\"stop!\\\"", StringEscapeUtils.escapeJson("He didn't say, \"stop!\"")); final String expected = "\\\"foo\\\" isn't \\\"bar\\\". specials: \\b\\r\\n\\f\\t\\\\\\/"; final String input = "\"foo\" isn't \"bar\". specials: \b\r\n\f\t\\/"; assertEquals(expected, StringEscapeUtils.escapeJson(input)); } @Test void testEscapeXml10() { assertEquals("a<b>c"d'e&f", StringEscapeUtils.escapeXml10("ac\"d'e&f")); assertEquals("a\tb\rc\nd", StringEscapeUtils.escapeXml10("a\tb\rc\nd"), "XML 1.0 should not escape \t \n \r"); assertEquals("ab", StringEscapeUtils.escapeXml10("a\u0000\u0001\u0008\u000b\u000c\u000e\u001fb"), "XML 1.0 should omit most #x0-x8 | #xb | #xc | #xe-#x19"); assertEquals("a\ud7ff \ue000b", StringEscapeUtils.escapeXml10("a\ud7ff\ud800 \udfff \ue000b"), "XML 1.0 should omit #xd800-#xdfff"); assertEquals("a\ufffdb", StringEscapeUtils.escapeXml10("a\ufffd\ufffe\uffffb"), "XML 1.0 should omit #xfffe | #xffff"); assertEquals("a\u007e„\u0085†Ÿ\u00a0b", StringEscapeUtils.escapeXml10("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"), "XML 1.0 should escape #x7f-#x84 | #x86 - #x9f, for XML 1.1 compatibility"); } @Test void testEscapeXml11() { assertEquals("a<b>c"d'e&f", StringEscapeUtils.escapeXml11("ac\"d'e&f")); assertEquals("a\tb\rc\nd", StringEscapeUtils.escapeXml11("a\tb\rc\nd"), "XML 1.1 should not escape \t \n \r"); assertEquals("ab", StringEscapeUtils.escapeXml11("a\u0000b"), "XML 1.1 should omit #x0"); assertEquals("a b", StringEscapeUtils.escapeXml11("a\u0001\u0008\u000b\u000c\u000e\u001fb"), "XML 1.1 should escape #x1-x8 | #xb | #xc | #xe-#x19"); assertEquals("a\u007e„\u0085†Ÿ\u00a0b", StringEscapeUtils.escapeXml11("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"), "XML 1.1 should escape #x7F-#x84 | #x86-#x9F"); assertEquals("a\ud7ff \ue000b", StringEscapeUtils.escapeXml11("a\ud7ff\ud800 \udfff \ue000b"), "XML 1.1 should omit #xd800-#xdfff"); assertEquals("a\ufffdb", StringEscapeUtils.escapeXml11("a\ufffd\ufffe\uffffb"), "XML 1.1 should omit #xfffe | #xffff"); } @Test void testEscapeXSI() { assertNull(null, escapeXSI(null)); assertEquals("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"", escapeXSI("He didn't say, \"Stop!\"")); assertEquals("\\\\", escapeXSI("\\")); assertEquals("", escapeXSI("\n")); } @Test void testLang313() { assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &")); } /** * Tests https://issues.apache.org/jira/browse/LANG-708 * * @throws IOException if an I/O error occurs */ @Test void testLang708() throws IOException { final byte[] inputBytes = Files.readAllBytes(Paths.get("src/test/resources/org/apache/commons/text/stringEscapeUtilsTestData.txt")); final String input = new String(inputBytes, StandardCharsets.UTF_8); final String escaped = StringEscapeUtils.escapeEcmaScript(input); // just the end: assertTrue(escaped.endsWith("}]"), escaped); // a little more: assertTrue(escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"), escaped); } /** * Tests https://issues.apache.org/jira/browse/LANG-911 */ @Test void testLang911() { final String bellsTest = "\ud83d\udc80\ud83d\udd14"; final String value = StringEscapeUtils.escapeJava(bellsTest); final String valueTest = StringEscapeUtils.unescapeJava(value); assertEquals(bellsTest, valueTest); } // Tests issue #38569 // https://issues.apache.org/bugzilla/show_bug.cgi?id=38569 @Test void testStandaloneAmphersand() { assertEquals("", StringEscapeUtils.unescapeHtml4("<P&O>")); assertEquals("test & <", StringEscapeUtils.unescapeHtml4("test & <")); assertEquals("", StringEscapeUtils.unescapeXml("<P&O>")); assertEquals("test & <", StringEscapeUtils.unescapeXml("test & <")); } @Test void testUnescapeCsvString() { assertEquals("foo.bar", StringEscapeUtils.unescapeCsv("foo.bar")); assertEquals("foo,bar", StringEscapeUtils.unescapeCsv("\"foo,bar\"")); assertEquals("foo\nbar", StringEscapeUtils.unescapeCsv("\"foo\nbar\"")); assertEquals("foo\rbar", StringEscapeUtils.unescapeCsv("\"foo\rbar\"")); assertEquals("foo\"bar", StringEscapeUtils.unescapeCsv("\"foo\"\"bar\"")); assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.unescapeCsv("foo\uD84C\uDFB4bar")); assertEquals("", StringEscapeUtils.unescapeCsv("")); assertNull(StringEscapeUtils.unescapeCsv(null)); assertEquals("foo.bar", StringEscapeUtils.unescapeCsv("\"foo.bar\"")); } @Test void testUnescapeCsvWriter() throws IOException { checkCsvUnescapeWriter("foo.bar", "foo.bar"); checkCsvUnescapeWriter("foo,bar", "\"foo,bar\""); checkCsvUnescapeWriter("foo\nbar", "\"foo\nbar\""); checkCsvUnescapeWriter("foo\rbar", "\"foo\rbar\""); checkCsvUnescapeWriter("foo\"bar", "\"foo\"\"bar\""); checkCsvUnescapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar"); checkCsvUnescapeWriter("", null); checkCsvUnescapeWriter("", ""); checkCsvUnescapeWriter("foo.bar", "\"foo.bar\""); } @Test void testUnescapeEcmaScript() { assertNull(StringEscapeUtils.unescapeEcmaScript(null)); assertEquals("8lvc1u+6B#-I", StringEscapeUtils.unescapeEcmaScript("8lvc1u+6B#-I")); assertEquals("", StringEscapeUtils.unescapeEcmaScript("")); assertEquals(">", StringEscapeUtils.unescapeEcmaScript(">")); } @Test void testUnescapeHexCharsHtml() { // Simple easy to grok test assertEquals("\u0080\u009F", StringEscapeUtils.unescapeHtml4("€Ÿ"), "hex number unescape"); assertEquals("\u0080\u009F", StringEscapeUtils.unescapeHtml4("€Ÿ"), "hex number unescape"); // Test all Character values: for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) { final char c2 = (char) (i + 1); final String expected = Character.toString(i) + Character.toString(c2); final String escapedC1 = "&#x" + Integer.toHexString(i) + ";"; final String escapedC2 = "&#x" + Integer.toHexString(c2) + ";"; assertEquals(expected, StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2), "hex number unescape index " + i); } } @Test void testUnescapeHtml3() { for (final String[] element : HTML_ESCAPES) { final String message = element[0]; final String expected = element[2]; final String original = element[1]; assertEquals(expected, StringEscapeUtils.unescapeHtml3(original), message); final StringWriter sw = new StringWriter(); try { StringEscapeUtils.UNESCAPE_HTML3.translate(original, sw); } catch (final IOException e) { // expected } final String actual = original == null ? null : sw.toString(); assertEquals(expected, actual, message); } // \u00E7 is a cedilla (c with wiggle under) // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly // on some locales assertEquals("Fran\u00E7ais", StringEscapeUtils.unescapeHtml3("Fran\u00E7ais"), "funny chars pass through OK"); assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml3("Hello&;World")); assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml3("Hello&#;World")); assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml3("Hello&# ;World")); assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml3("Hello&##;World")); } @Test void testUnescapeHtml4() { for (final String[] element : HTML_ESCAPES) { final String message = element[0]; final String expected = element[2]; final String original = element[1]; assertEquals(expected, StringEscapeUtils.unescapeHtml4(original), message); final StringWriter sw = new StringWriter(); try { StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw); } catch (final IOException e) { // expected } final String actual = original == null ? null : sw.toString(); assertEquals(expected, actual, message); } // \u00E7 is a cedilla (c with wiggle under) // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly // on some locales assertEquals("Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"), "funny chars pass through OK"); assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World")); assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World")); assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World")); assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World")); } @Test void testUnescapeJava() throws IOException { assertNull(StringEscapeUtils.unescapeJava(null)); try { StringEscapeUtils.UNESCAPE_JAVA.translate(null, null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } try { StringEscapeUtils.UNESCAPE_JAVA.translate("", null); fail("Exception expected!"); } catch (final IOException ex) { fail("Exception expected!"); } catch (final IllegalArgumentException ex) { // expected } assertThrows(RuntimeException.class, () -> StringEscapeUtils.unescapeJava("\\u02-3")); assertUnescapeJava("", ""); assertUnescapeJava("test", "test"); assertUnescapeJava("\ntest\b", "\\ntest\\b"); assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b"); assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r"); assertUnescapeJava("", "\\"); // foo assertUnescapeJava("\uABCDx", "\\uabcdx", "lowercase Unicode"); assertUnescapeJava("\uABCDx", "\\uABCDx", "uppercase Unicode"); assertUnescapeJava("\uABCD", "\\uabcd", "Unicode as final character"); } @Test void testUnescapeJson() { final String jsonString = "{\"age\":100,\"name\":\"kyong.com\n\",\"messages\":[\"msg 1\",\"msg 2\",\"msg 3\"]}"; assertEquals("", StringEscapeUtils.unescapeJson("")); assertEquals(" ", StringEscapeUtils.unescapeJson(" ")); assertEquals("a:b", StringEscapeUtils.unescapeJson("a:b")); assertEquals(jsonString, StringEscapeUtils.unescapeJson(jsonString)); } @Test // TEXT-120 void testUnescapeJsonDoubleQuoteAndForwardSlash() { final String escapedJsonString = "double quote: \\\" and a forward slash: \\/"; final String jsonString = "double quote: \" and a forward slash: /"; assertEquals(jsonString, StringEscapeUtils.unescapeJson(escapedJsonString)); } @Test void testUnescapeUnknownEntity() { assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;")); } /** * Reverse of the above. * * @see LANG-729 */ @Test void testUnescapeXmlSupplementaryCharacters() { assertEquals("\uD84C\uDFB4", StringEscapeUtils.unescapeXml("𣎴"), "Supplementary character must be represented using a single escape"); assertEquals("a b c \uD84C\uDFB4", StringEscapeUtils.unescapeXml("a b c 𣎴"), "Supplementary characters mixed with basic characters should be decoded correctly"); } @Test void testUnscapeXSI() { assertNull(null, unescapeXSI(null)); assertEquals("\"", unescapeXSI("\\\"")); assertEquals("He didn't say, \"Stop!\"", unescapeXSI("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"")); assertEquals("\\", unescapeXSI("\\\\")); assertEquals("", unescapeXSI("\\")); } } StringSubstitutorOssFuzzTest.java000066400000000000000000000053431511432740600353420ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import org.junit.jupiter.api.Test; class StringSubstitutorOssFuzzTest { private String readAllString(final String testCase) throws IOException { final byte[] allBytes = Files.readAllBytes(Paths.get("src/test/resources/org/apache/commons/text/oss-fuzz/" + testCase)); return new String(allBytes, StandardCharsets.UTF_8); } /** * Tests OSS-Fuzz issue 42522985. * * apache-commons-text:StringSubstitutorInterpolatorFuzzer: Security exception in java.base/java.util.Arrays.copyOf * * https://issues.oss-fuzz.com/issues/42522985 */ @Test void test42522985() throws IOException { StringSubstitutor.createInterpolator().replace(readAllString("clusterfuzz-testcase-StringSubstitutorInterpolatorFuzzer-6287296750813184")); } /** * Tests OSS-Fuzz issue 42527553. * * apache-commons-text:StringSubstitutorInterpolatorFuzzer: Security exception in java.base/java.util.Arrays.copyOf * * https://issues.oss-fuzz.com/issues/42527553 */ @Test void test42527553() { StringSubstitutor.createInterpolator().replace("${date:swswswswsws\177sw\001\000swswswswswwswsswswswsws\177sw\001\000swswswsswswswswswswswswswswsws}"); } /** * Tests OSS-Fuzz issue 42527776. * * apache-commons-text:StringSubstitutorInterpolatorFuzzer: Security exception in java.base/java.util.Arrays.copyOf * * https://issues.oss-fuzz.com/issues/42527776 */ @Test void test42527776() throws IOException { assertThrows(IllegalArgumentException.class, () -> StringSubstitutor.createInterpolator() .replace(readAllString("clusterfuzz-testcase-StringSubstitutorInterpolatorFuzzer-5149898315268096"))); } } StringSubstitutorTest.java000066400000000000000000001204771511432740600340040ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemProperties; import org.apache.commons.lang3.mutable.MutableObject; import org.apache.commons.text.lookup.StringLookup; import org.apache.commons.text.lookup.StringLookupFactory; import org.apache.commons.text.matcher.StringMatcher; import org.apache.commons.text.matcher.StringMatcherFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; /** * Test class for {@link StringSubstitutor}. */ @TestMethodOrder(MethodOrderer.MethodName.class) // temp, for my sanity during dev public class StringSubstitutorTest { private static final String ACTUAL_ANIMAL = "quick brown fox"; private static final String ACTUAL_TARGET = "lazy dog"; private static final String CLASSIC_RESULT = "The quick brown fox jumps over the lazy dog."; private static final String CLASSIC_TEMPLATE = "The ${animal} jumps over the ${target}."; private static final String EMPTY_EXPR = "${}"; protected Map values; private void assertEqualsCharSeq(final CharSequence expected, final CharSequence actual) { assertEquals(expected, actual, () -> String.format("expected.length()=%,d, actual.length()=%,d", StringUtils.length(expected), StringUtils.length(actual))); } protected void doNotReplace(final String replaceTemplate) throws IOException { doTestNoReplace(new StringSubstitutor(values), replaceTemplate); } protected void doReplace(final String expectedResult, final String replaceTemplate, final boolean substring) throws IOException { doTestReplace(new StringSubstitutor(values), expectedResult, replaceTemplate, substring); } protected void doTestNoReplace(final StringSubstitutor substitutor, final String replaceTemplate) throws IOException { if (replaceTemplate == null) { assertNull(replace(substitutor, (String) null)); assertNull(substitutor.replace((String) null, 0, 100)); assertNull(substitutor.replace((char[]) null)); assertNull(substitutor.replace((char[]) null, 0, 100)); assertNull(substitutor.replace((StringBuffer) null)); assertNull(substitutor.replace((StringBuffer) null, 0, 100)); assertNull(substitutor.replace((TextStringBuilder) null)); assertNull(substitutor.replace((TextStringBuilder) null, 0, 100)); assertNull(substitutor.replace((Object) null)); assertFalse(substitutor.replaceIn((StringBuffer) null)); assertFalse(substitutor.replaceIn((StringBuffer) null, 0, 100)); assertFalse(substitutor.replaceIn((TextStringBuilder) null)); assertFalse(substitutor.replaceIn((TextStringBuilder) null, 0, 100)); } else { assertEquals(replaceTemplate, replace(substitutor, replaceTemplate)); final TextStringBuilder builder = new TextStringBuilder(replaceTemplate); assertFalse(substitutor.replaceIn(builder)); assertEquals(replaceTemplate, builder.toString()); } } protected void doTestReplace(final StringSubstitutor sub, final String expectedResult, final String replaceTemplate, final boolean substring) throws IOException { final String expectedShortResult = substring ? expectedResult.substring(1, expectedResult.length() - 1) : expectedResult; // replace using String final String actual = replace(sub, replaceTemplate); assertEquals(expectedResult, actual, () -> String.format("Index of difference: %,d", StringUtils.indexOfDifference(expectedResult, actual))); if (substring) { assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2)); } // replace using char[] final char[] chars = replaceTemplate.toCharArray(); assertEquals(expectedResult, sub.replace(chars)); if (substring) { assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2)); } // replace using StringBuffer StringBuffer buf = new StringBuffer(replaceTemplate); assertEquals(expectedResult, sub.replace(buf)); if (substring) { assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2)); } // replace using StringBuilder StringBuilder builder = new StringBuilder(replaceTemplate); assertEquals(expectedResult, sub.replace(builder)); if (substring) { assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2)); } // replace using TextStringBuilder TextStringBuilder bld = new TextStringBuilder(replaceTemplate); assertEquals(expectedResult, sub.replace(bld)); if (substring) { assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2)); } // replace using object final MutableObject obj = new MutableObject<>(replaceTemplate); // toString returns template assertEquals(expectedResult, sub.replace(obj)); // replace in StringBuffer buf = new StringBuffer(replaceTemplate); assertTrue(sub.replaceIn(buf), replaceTemplate); assertEquals(expectedResult, buf.toString()); if (substring) { buf = new StringBuffer(replaceTemplate); assertTrue(sub.replaceIn(buf, 1, buf.length() - 2)); assertEquals(expectedResult, buf.toString()); // expect full result as remainder is untouched } // replace in StringBuilder builder = new StringBuilder(replaceTemplate); assertTrue(sub.replaceIn(builder)); assertEquals(expectedResult, builder.toString()); if (substring) { builder = new StringBuilder(replaceTemplate); assertTrue(sub.replaceIn(builder, 1, builder.length() - 2)); assertEquals(expectedResult, builder.toString()); // expect full result as remainder is untouched } // replace in TextStringBuilder bld = new TextStringBuilder(replaceTemplate); assertTrue(sub.replaceIn(bld)); assertEquals(expectedResult, bld.toString()); if (substring) { bld = new TextStringBuilder(replaceTemplate); assertTrue(sub.replaceIn(bld, 1, bld.length() - 2)); assertEquals(expectedResult, bld.toString()); // expect full result as remainder is untouched } } /** * For subclasses to override. * * @throws IOException Thrown by subclasses. */ protected String replace(final StringSubstitutor stringSubstitutor, final String template) throws IOException { return stringSubstitutor.replace(template); } @BeforeEach public void setUp() throws Exception { values = new HashMap<>(); // shortest key and value. values.put("a", "1"); values.put("aa", "11"); values.put("aaa", "111"); values.put("b", "2"); values.put("bb", "22"); values.put("bbb", "222"); values.put("a2b", "b"); // normal key and value. values.put("animal", ACTUAL_ANIMAL); values.put("target", ACTUAL_TARGET); } @AfterEach public void tearDown() throws Exception { values = null; } @Test void testConstructorNullMap() { final Map parameters = null; final StringSubstitutor s = new StringSubstitutor(parameters, "prefix", "suffix"); assertNull(s.getStringLookup().apply("X")); assertNull(s.getStringLookup().lookup("X")); } @Test void testConstructorStringSubstitutor() { final StringSubstitutor source = new StringSubstitutor(); source.setDisableSubstitutionInValues(true); source.setEnableSubstitutionInVariables(true); source.setEnableUndefinedVariableException(true); source.setEscapeChar('e'); source.setValueDelimiter('d'); source.setVariablePrefix('p'); source.setVariableResolver(StringLookupFactory.INSTANCE.nullStringLookup()); source.setVariableSuffix('s'); // final StringSubstitutor target = new StringSubstitutor(source); // assertTrue(target.isDisableSubstitutionInValues()); assertTrue(target.isEnableSubstitutionInVariables()); assertTrue(target.isEnableUndefinedVariableException()); assertEquals('e', target.getEscapeChar()); assertTrue(target.getValueDelimiterMatcher().toString().endsWith("['d']"), target.getValueDelimiterMatcher().toString()); assertTrue(target.getVariablePrefixMatcher().toString().endsWith("['p']"), target.getValueDelimiterMatcher().toString()); assertTrue(target.getVariableSuffixMatcher().toString().endsWith("['s']"), target.getValueDelimiterMatcher().toString()); } @Test void testDetectsCyclicSubstitution() { final Map map = new HashMap<>(); map.put("name", ""); assertThrows(IllegalStateException.class, () -> StringSubstitutor.replace("Hi !", map, "<", ">")); } /** * Tests get set. */ @Test void testGetSetEscape() { final StringSubstitutor sub = new StringSubstitutor(); assertEquals('$', sub.getEscapeChar()); sub.setEscapeChar('<'); assertEquals('<', sub.getEscapeChar()); } /** * Test for LANG-1055: StringSubstitutor.replaceSystemProperties does not work consistently */ @Test void testLANG1055() { System.setProperty("test_key", "test_value"); final String expected = StringSubstitutor.replace("test_key=${test_key}", System.getProperties()); final String actual = StringSubstitutor.replaceSystemProperties("test_key=${test_key}"); assertEquals(expected, actual); } /** * Tests interpolation with weird boundary patterns. */ @Test void testReplace_JiraText178_WeirdPatterns1() throws IOException { doNotReplace("$${"); doNotReplace("$${a"); doNotReplace("$$${"); doNotReplace("$$${a"); doNotReplace("$${${a"); doNotReplace("${${a}"); // "${a" is not a registered variable name. doNotReplace("${$${a}"); } /** * Tests interpolation with weird boundary patterns. */ @Test void testReplace_JiraText178_WeirdPatterns2() throws IOException { doReplace("${1}", "$${${a}}", false); } /** * Tests interpolation with weird boundary patterns. */ @Test @Disabled void testReplace_JiraText178_WeirdPatterns3() throws IOException { doReplace("${${a}", "$${${a}", false); // not "$${1" or "${1" } /** * Tests adjacent keys. */ @Test void testReplaceAdjacentAtEnd() throws IOException { values.put("code", "GBP"); values.put("amount", "12.50"); final StringSubstitutor sub = new StringSubstitutor(values); assertEqualsCharSeq("Amount is GBP12.50", replace(sub, "Amount is ${code}${amount}")); } /** * Tests adjacent keys. */ @Test void testReplaceAdjacentAtStart() throws IOException { values.put("code", "GBP"); values.put("amount", "12.50"); final StringSubstitutor sub = new StringSubstitutor(values); assertEqualsCharSeq("GBP12.50 charged", replace(sub, "${code}${amount} charged")); } /** * Tests key replace changing map after initialization (not recommended). */ @Test void testReplaceChangedMap() throws IOException { final StringSubstitutor sub = new StringSubstitutor(values); // no map change final String template = CLASSIC_TEMPLATE; assertEqualsCharSeq(CLASSIC_RESULT, replace(sub, template)); // map change values.put("target", "moon"); assertEqualsCharSeq("The quick brown fox jumps over the moon.", replace(sub, template)); } /** * Tests complex escaping. */ @Test void testReplaceComplexEscaping() throws IOException { doReplace("${1}", "$${${a}}", false); doReplace("${11}", "$${${aa}}", false); doReplace("${111}", "$${${aaa}}", false); doReplace("${quick brown fox}", "$${${animal}}", false); doReplace("The ${quick brown fox} jumps over the lazy dog.", "The $${${animal}} jumps over the ${target}.", true); doReplace("${${a}}", "$${$${a}}", false); doReplace("${${aa}}", "$${$${aa}}", false); doReplace("${${aaa}}", "$${$${aaa}}", false); doReplace("${${animal}}", "$${$${animal}}", false); doReplace(".${${animal}}", ".$${$${animal}}", false); doReplace("${${animal}}.", "$${$${animal}}.", false); doReplace(".${${animal}}.", ".$${$${animal}}.", false); doReplace("The ${${animal}} jumps over the lazy dog.", "The $${$${animal}} jumps over the ${target}.", true); doReplace("The ${quick brown fox} jumps over the lazy dog. ${1234567890}.", "The $${${animal}} jumps over the ${target}. $${${undefined.number:-1234567890}}.", true); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKey() throws IOException { doReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyExtraFirst() throws IOException { assertEqualsCharSeq("." + EMPTY_EXPR, replace(new StringSubstitutor(values), "." + EMPTY_EXPR)); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyExtraLast() throws IOException { assertEqualsCharSeq(EMPTY_EXPR + ".", replace(new StringSubstitutor(values), EMPTY_EXPR + ".")); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyOnly() throws IOException { assertEquals(EMPTY_EXPR, replace(new StringSubstitutor(values), EMPTY_EXPR)); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyShortest() throws IOException { doNotReplace(EMPTY_EXPR); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyWithDefault() throws IOException { doReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyWithDefaultOnly() throws IOException { doReplace("animal", "${:-animal}", false); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyWithDefaultOnlyEmpty() throws IOException { doReplace("", "${:-}", false); } /** * Tests when no variable name. */ @Test void testReplaceEmptyKeyWithDefaultOnlyShortest() throws IOException { doReplace("a", "${:-a}", false); } /** * Tests replace with null. */ @Test void testReplaceEmptyString() throws IOException { doNotReplace(StringUtils.EMPTY); } /** * Tests escaping. */ @Test void testReplaceEscaping() throws IOException { doReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true); doReplace("${a}", "$${a}", false); doReplace("${a${a}}", "$${a$${a}}", false); doReplace("${a${a${a}}}", "$${a$${a$${a}}}", false); } /** * Tests replace with fail on undefined variable. */ @Test void testReplaceFailOnUndefinedVariable() throws IOException { values.put("animal.1", "fox"); values.put("animal.2", "mouse"); values.put("species", "2"); final StringSubstitutor sub = new StringSubstitutor(values); sub.setEnableUndefinedVariableException(true); assertEquals("Cannot resolve variable 'animal.${species' (enableSubstitutionInVariables=false).", assertThrows(IllegalArgumentException.class, () -> replace(sub, "The ${animal.${species}} jumps over the ${target}.")).getMessage()); assertEquals("Cannot resolve variable 'animal.${species:-1' (enableSubstitutionInVariables=false).", assertThrows(IllegalArgumentException.class, () -> replace(sub, "The ${animal.${species:-1}} jumps over the ${target}.")).getMessage()); assertEquals("Cannot resolve variable 'unknown' (enableSubstitutionInVariables=false).", assertThrows(IllegalArgumentException.class, () -> replace(sub, "The ${test:-statement} is a sample for missing ${unknown}.")).getMessage()); // if default value is available, exception will not be thrown assertEqualsCharSeq("The statement is a sample for missing variable.", replace(sub, "The ${test:-statement} is a sample for missing ${unknown:-variable}.")); assertEqualsCharSeq("The fox jumps over the lazy dog.", replace(sub, "The ${animal.1} jumps over the ${target}.")); } /** * Tests whether replace with fail on undefined variable with substitution in variable names enabled. */ @Test void testReplaceFailOnUndefinedVariableWithReplaceInVariable() throws IOException { values.put("animal.1", "fox"); values.put("animal.2", "mouse"); values.put("species", "2"); values.put("statement.1", "2"); values.put("recursive", "1"); values.put("word", "variable"); values.put("testok.2", "statement"); final StringSubstitutor sub = new StringSubstitutor(values); sub.setEnableUndefinedVariableException(true); sub.setEnableSubstitutionInVariables(true); assertEqualsCharSeq("The mouse jumps over the lazy dog.", replace(sub, "The ${animal.${species}} jumps over the ${target}.")); values.put("species", "1"); assertEqualsCharSeq("The fox jumps over the lazy dog.", replace(sub, "The ${animal.${species}} jumps over the ${target}.")); // exception is thrown here because variable with name test.1 is missing assertEquals("Cannot resolve variable 'statement' (enableSubstitutionInVariables=true).", assertThrows(IllegalArgumentException.class, () -> replace(sub, "The ${test.${statement}} is a sample for missing ${word}.")).getMessage()); // exception is thrown here because variable with name test.2 is missing assertEquals("Cannot resolve variable 'test.2' (enableSubstitutionInVariables=true).", assertThrows(IllegalArgumentException.class, () -> replace(sub, "The ${test.${statement.${recursive}}} is a sample for missing ${word}.")) .getMessage()); assertEqualsCharSeq("statement", replace(sub, "${testok.${statement.${recursive}}}")); assertEqualsCharSeq("${testok.2}", replace(sub, "$${testok.${statement.${recursive}}}")); assertEqualsCharSeq("The statement is a sample for missing variable.", replace(sub, "The ${testok.${statement.${recursive}}} is a sample for missing ${word}.")); } /** * Tests when no incomplete prefix. */ @Test void testReplaceIncompletePrefix() throws IOException { doReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true); } @Test void testReplaceInTakingStringBufferWithNonNull() { final StringSubstitutor strSubstitutor = new StringSubstitutor(new HashMap<>(), "WV@i#y?N*[", "WV@i#y?N*[", '*'); assertFalse(strSubstitutor.isPreserveEscapes()); assertFalse(strSubstitutor.replaceIn(new StringBuffer("WV@i#y?N*["))); assertEquals('*', strSubstitutor.getEscapeChar()); } @Test void testReplaceInTakingStringBuilderWithNonNull() { final StringLookup strLookup = StringLookupFactory.INSTANCE.systemPropertyStringLookup(); final StringSubstitutor strSubstitutor = new StringSubstitutor(strLookup, "b map = new HashMap<>(); final StringSubstitutor strSubstitutor = new StringSubstitutor(map, StringUtils.EMPTY, StringUtils.EMPTY, 'T', "K+<'f"); assertFalse(strSubstitutor.replaceIn((StringBuilder) null)); } @Test void testReplaceInTakingTwoAndThreeIntsReturningFalse() { final Map hashMap = new HashMap<>(); final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.mapStringLookup(hashMap); final StringMatcher strMatcher = StringMatcherFactory.INSTANCE.tabMatcher(); final StringSubstitutor strSubstitutor = new StringSubstitutor(mapStringLookup, strMatcher, strMatcher, 'b', strMatcher); assertFalse(strSubstitutor.replaceIn((StringBuilder) null, 1315, -1369)); assertEquals('b', strSubstitutor.getEscapeChar()); assertFalse(strSubstitutor.isPreserveEscapes()); } /** * Tests whether a variable can be replaced in a variable name. */ @Test void testReplaceInVariable() throws IOException { values.put("animal.1", "fox"); values.put("animal.2", "mouse"); values.put("species", "2"); final StringSubstitutor sub = new StringSubstitutor(values); sub.setEnableSubstitutionInVariables(true); assertEqualsCharSeq("The mouse jumps over the lazy dog.", replace(sub, "The ${animal.${species}} jumps over the ${target}.")); values.put("species", "1"); assertEqualsCharSeq("The fox jumps over the lazy dog.", replace(sub, "The ${animal.${species}} jumps over the ${target}.")); assertEqualsCharSeq("The fox jumps over the lazy dog.", replace(sub, "The ${unknown.animal.${unknown.species:-1}:-fox} jumps over the ${unknow.target:-lazy dog}.")); } /** * Tests whether substitution in variable names is disabled per default. */ @Test void testReplaceInVariableDisabled() throws IOException { values.put("animal.1", "fox"); values.put("animal.2", "mouse"); values.put("species", "2"); final StringSubstitutor sub = new StringSubstitutor(values); assertEqualsCharSeq("The ${animal.${species}} jumps over the lazy dog.", replace(sub, "The ${animal.${species}} jumps over the ${target}.")); assertEqualsCharSeq("The ${animal.${species:-1}} jumps over the lazy dog.", replace(sub, "The ${animal.${species:-1}} jumps over the ${target}.")); } /** * Tests complex and recursive substitution in variable names. */ @Test void testReplaceInVariableRecursive() throws IOException { values.put("animal.2", "brown fox"); values.put("animal.1", "white mouse"); values.put("color", "white"); values.put("species.white", "1"); values.put("species.brown", "2"); final StringSubstitutor sub = new StringSubstitutor(values); sub.setEnableSubstitutionInVariables(true); assertEqualsCharSeq("white mouse", replace(sub, "${animal.${species.${color}}}")); assertEqualsCharSeq("The white mouse jumps over the lazy dog.", replace(sub, "The ${animal.${species.${color}}} jumps over the ${target}.")); assertEqualsCharSeq("The brown fox jumps over the lazy dog.", replace(sub, "The ${animal.${species.${unknownColor:-brown}}} jumps over the ${target}.")); } /** * Tests when no variable name. */ @Test void testReplaceKeyStartChars() throws IOException { final String substring = StringSubstitutor.DEFAULT_VAR_START + "a"; assertEqualsCharSeq(substring, replace(new StringSubstitutor(values), substring)); } /** * Tests when no variable name. */ @Test void testReplaceKeyStartChars1Only() throws IOException { final String substring = StringSubstitutor.DEFAULT_VAR_START.substring(0, 1); assertEqualsCharSeq(substring, replace(new StringSubstitutor(values), substring)); } /** * Tests when no variable name. */ @Test void testReplaceKeyStartChars2Only() throws IOException { final String substring = StringSubstitutor.DEFAULT_VAR_START.substring(0, 2); assertEqualsCharSeq(substring, replace(new StringSubstitutor(values), substring)); } /** * Tests when no prefix or suffix. */ @Test void testReplaceNoPrefixNoSuffix() throws IOException { doReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true); } /** * Tests when suffix but no prefix. */ @Test void testReplaceNoPrefixSuffix() throws IOException { doReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true); } /** * Tests replace with no variables. */ @Test void testReplaceNoVariables() throws IOException { doNotReplace("The balloon arrived."); } /** * Tests replace with null. */ @Test void testReplaceNull() throws IOException { doNotReplace(null); } /** * Tests simple key replace. */ @Test void testReplacePartialString_noReplace() { final StringSubstitutor sub = new StringSubstitutor(); assertEqualsCharSeq("${animal} jumps", sub.replace(CLASSIC_TEMPLATE, 4, 15)); } /** * Tests when prefix but no suffix. */ @Test void testReplacePrefixNoSuffix() throws IOException { doReplace("The ${animal jumps over the ${target} lazy dog.", "The ${animal jumps over the ${target} ${target}.", true); } /** * Tests simple recursive replace. */ @Test void testReplaceRecursive() throws IOException { values.put("animal", "${critter}"); values.put("target", "${pet}"); values.put("pet", "${petCharacteristic} dog"); values.put("petCharacteristic", "lazy"); values.put("critter", "${critterSpeed} ${critterColor} ${critterType}"); values.put("critterSpeed", "quick"); values.put("critterColor", "brown"); values.put("critterType", "fox"); doReplace(CLASSIC_RESULT, CLASSIC_TEMPLATE, true); values.put("pet", "${petCharacteristicUnknown:-lazy} dog"); doReplace(CLASSIC_RESULT, CLASSIC_TEMPLATE, true); } /** * Tests simple key replace. */ @Test void testReplaceSimple() throws IOException { doReplace(CLASSIC_RESULT, CLASSIC_TEMPLATE, true); } /** * Tests simple key replace. */ @Test void testReplaceSimpleKeySize1() throws IOException { doReplace("1", "${a}", false); } /** * Tests simple key replace. */ @Test void testReplaceSimpleKeySize2() throws IOException { doReplace("11", "${aa}", false); } /** * Tests simple key replace. */ @Test void testReplaceSimpleKeySize3() throws IOException { doReplace("111", "${aaa}", false); } @Test void testReplaceTakingCharSequenceReturningNull() { final StringSubstitutor strSubstitutor = new StringSubstitutor((StringLookup) null); assertNull(strSubstitutor.replace((CharSequence) null)); assertFalse(strSubstitutor.isPreserveEscapes()); assertEquals('$', strSubstitutor.getEscapeChar()); } @Test void testReplaceTakingThreeArgumentsThrowsNullPointerException() { assertThrows(NullPointerException.class, () -> StringSubstitutor.replace(null, (Properties) null)); } @Test void testReplaceThrowsStringIndexOutOfBoundsException() { final StringSubstitutor sub = new StringSubstitutor(); // replace(char[], int, int) final char[] emptyCharArray = {}; // offset greater than array length assertThrows(StringIndexOutOfBoundsException.class, () -> sub.replace(emptyCharArray, 0, 1)); // source != null && (offset > source.length || offset < 0) assertThrows(StringIndexOutOfBoundsException.class, () -> sub.replace(emptyCharArray, 1, 0)); // replace(String, int, int) // offset greater than source length assertThrows(StringIndexOutOfBoundsException.class, () -> sub.replace("", 1, 1)); // source != null && offset >= 0 && offset <= source.length() && (length > -offset + source.length() || length < 0) assertThrows(StringIndexOutOfBoundsException.class, () -> sub.replace("", 0, 1)); } /** * Tests replace creates output same as input. */ @Test void testReplaceToIdentical() throws IOException { values.put("animal", "$${${thing}}"); values.put("thing", "animal"); doReplace("The ${animal} jumps.", "The ${animal} jumps.", true); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownKey() throws IOException { doReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownKeyDefaultValue() throws IOException { doReplace("The ${person} jumps over the lazy dog. 1234567890.", "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownKeyOnly() throws IOException { final String expected = "${person}"; assertEqualsCharSeq(expected, replace(new StringSubstitutor(values), expected)); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownKeyOnlyExtraFirst() throws IOException { final String expected = ".${person}"; assertEqualsCharSeq(expected, replace(new StringSubstitutor(values), expected)); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownKeyOnlyExtraLast() throws IOException { final String expected = "${person}."; assertEqualsCharSeq(expected, replace(new StringSubstitutor(values), expected)); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownShortestKeyOnly() throws IOException { final String expected = "${U}"; assertEqualsCharSeq(expected, replace(new StringSubstitutor(values), expected)); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownShortestKeyOnlyExtraFirst() throws IOException { final String expected = ".${U}"; assertEqualsCharSeq(expected, replace(new StringSubstitutor(values), expected)); } /** * Tests unknown key replace. */ @Test void testReplaceUnknownShortestKeyOnlyExtraLast() throws IOException { final String expected = "${U}."; assertEqualsCharSeq(expected, replace(new StringSubstitutor(values), expected)); } /** * Tests simple key replace. */ @Test void testReplaceVariablesCount1() throws IOException { doReplace(ACTUAL_ANIMAL, "${animal}", false); } /** * Tests escaping. */ @Test void testReplaceVariablesCount1Escaping2To1() throws IOException { doReplace("${a}", "$${a}", false); doReplace("${animal}", "$${animal}", false); } /** * Tests escaping. */ @Test void testReplaceVariablesCount1Escaping3To2() throws IOException { doReplace("$${a}", "$$${a}", false); doReplace("$${animal}", "$$${animal}", false); } /** * Tests escaping. */ @Test void testReplaceVariablesCount1Escaping4To3() throws IOException { doReplace("$$${a}", "$$$${a}", false); doReplace("$$${animal}", "$$$${animal}", false); } /** * Tests escaping. */ @Test void testReplaceVariablesCount1Escaping5To4() throws IOException { doReplace("$$$${a}", "$$$$${a}", false); doReplace("$$$${animal}", "$$$$${animal}", false); } /** * Tests escaping. */ @Test void testReplaceVariablesCount1Escaping6To4() throws IOException { doReplace("$$$$${a}", "$$$$$${a}", false); doReplace("$$$$${animal}", "$$$$$${animal}", false); } /** * Tests simple key replace. */ @Test void testReplaceVariablesCount2() throws IOException { // doTestReplace("12", "${a}${b}", false); doReplace("1122", "${aa}${bb}", false); doReplace(ACTUAL_ANIMAL + ACTUAL_ANIMAL, "${animal}${animal}", false); doReplace(ACTUAL_TARGET + ACTUAL_TARGET, "${target}${target}", false); doReplace(ACTUAL_ANIMAL + ACTUAL_TARGET, "${animal}${target}", false); } /** * Tests simple key replace. */ @Test void testReplaceVariablesCount2NonAdjacent() throws IOException { doReplace("1 2", "${a} ${b}", false); doReplace("11 22", "${aa} ${bb}", false); doReplace(ACTUAL_ANIMAL + " " + ACTUAL_ANIMAL, "${animal} ${animal}", false); doReplace(ACTUAL_ANIMAL + " " + ACTUAL_ANIMAL, "${animal} ${animal}", false); doReplace(ACTUAL_ANIMAL + " " + ACTUAL_ANIMAL, "${animal} ${animal}", false); } /** * Tests simple key replace. */ @Test void testReplaceVariablesCount3() throws IOException { doReplace("121", "${a}${b}${a}", false); doReplace("112211", "${aa}${bb}${aa}", false); doReplace(ACTUAL_ANIMAL + ACTUAL_ANIMAL + ACTUAL_ANIMAL, "${animal}${animal}${animal}", false); doReplace(ACTUAL_TARGET + ACTUAL_TARGET + ACTUAL_TARGET, "${target}${target}${target}", false); } /** * Tests simple key replace. */ @Test void testReplaceVariablesCount3NonAdjacent() throws IOException { doReplace("1 2 1", "${a} ${b} ${a}", false); doReplace("11 22 11", "${aa} ${bb} ${aa}", false); doReplace(ACTUAL_ANIMAL + " " + ACTUAL_ANIMAL + " " + ACTUAL_ANIMAL, "${animal} ${animal} ${animal}", false); doReplace(ACTUAL_TARGET + " " + ACTUAL_TARGET + " " + ACTUAL_TARGET, "${target} ${target} ${target}", false); } /** * Tests interpolation with weird boundary patterns. */ @Test void testReplaceWeirdPattens() throws IOException { doNotReplace(StringUtils.EMPTY); doNotReplace(EMPTY_EXPR); doNotReplace("${ }"); doNotReplace("${\t}"); doNotReplace("${\n}"); doNotReplace("${\b}"); doNotReplace("${"); doNotReplace("$}"); doNotReplace("$$}"); doNotReplace("}"); doNotReplace("${}$"); doNotReplace("${}$$"); doNotReplace("${${"); doNotReplace("${${}}"); doNotReplace("${$${}}"); doNotReplace("${$$${}}"); doNotReplace("${$$${$}}"); doNotReplace("${${}}"); doNotReplace("${${ }}"); // doNotReplace("${$${a}}"); doNotReplace("${$$${a}}"); doNotReplace("${${a}}"); doNotReplace("${${${a}"); doNotReplace("${ ${a}"); doNotReplace("${ ${ ${a}"); // doReplace("${1}", "$${${a}}", false); doReplace("${ 1}", "$${ ${a}}", false); doReplace("${12}", "$${${a}${b}}", false); doReplace("${ 1 2 }", "$${ ${a} ${b} }", false); doReplace("${${${a}2", "${${${a}${b}", false); } /** * Tests protected. */ @Test void testResolveVariable() { final TextStringBuilder builder = new TextStringBuilder("Hi ${name}!"); final Map map = new HashMap<>(); map.put("name", "commons"); final StringSubstitutor sub = new StringSubstitutor(map) { @Override protected String resolveVariable(final String variableName, final TextStringBuilder buf, final int startPos, final int endPos) { assertEquals("name", variableName); assertSame(builder, buf); assertEquals(3, startPos); assertEquals(10, endPos); return "jakarta"; } }; sub.replaceIn(builder); assertEqualsCharSeq("Hi jakarta!", builder.toString()); } @Test void testSamePrefixAndSuffix() { final Map map = new HashMap<>(); map.put("greeting", "Hello"); map.put(" there ", "XXX"); map.put("name", "commons"); assertEqualsCharSeq("Hi commons!", StringSubstitutor.replace("Hi @name@!", map, "@", "@")); assertEqualsCharSeq("Hello there commons!", StringSubstitutor.replace("@greeting@ there @name@!", map, "@", "@")); } /** * Tests static. */ @Test void testStaticReplace() { final Map map = new HashMap<>(); map.put("name", "commons"); assertEqualsCharSeq("Hi commons!", StringSubstitutor.replace("Hi ${name}!", map)); } /** * Tests static. */ @Test void testStaticReplacePrefixSuffix() { final Map map = new HashMap<>(); map.put("name", "commons"); assertEqualsCharSeq("Hi commons!", StringSubstitutor.replace("Hi !", map, "<", ">")); } /** * Tests interpolation with system properties. */ @Test void testStaticReplaceSystemProperties() { final TextStringBuilder buf = new TextStringBuilder(); buf.append("Hi ").append(SystemProperties.getUserName()); buf.append(", you are working with "); buf.append(SystemProperties.getOsName()); buf.append(", your home directory is "); buf.append(SystemProperties.getUserHome()).append('.'); assertEqualsCharSeq(buf.toString(), StringSubstitutor.replaceSystemProperties("Hi ${user.name}, you are " + "working with ${os.name}, your home directory is ${user.home}.")); } /** * Tests interpolation with system properties. */ @Test void testStaticReplaceSystemPropertiesWithUpdate() { System.setProperty("foo", "bar1"); try { assertEqualsCharSeq("bar1", StringSubstitutor.replaceSystemProperties("${foo}")); System.setProperty("foo", "bar2"); assertEqualsCharSeq("bar2", StringSubstitutor.replaceSystemProperties("${foo}")); } finally { System.getProperties().remove("foo"); } } /** * Test the replace of a properties object */ @Test void testSubstituteDefaultProperties() { final String org = "${doesnotwork}"; System.setProperty("doesnotwork", "It works!"); // create a new Properties object with the System.getProperties as default final Properties props = new Properties(System.getProperties()); assertEqualsCharSeq("It works!", StringSubstitutor.replace(org, props)); } @Test void testSubstitutePreserveEscape() throws IOException { final String org = "${not-escaped} $${escaped}"; final Map map = new HashMap<>(); map.put("not-escaped", "value"); final StringSubstitutor sub = new StringSubstitutor(map, "${", "}", '$'); assertFalse(sub.isPreserveEscapes()); assertEqualsCharSeq("value ${escaped}", replace(sub, org)); sub.setPreserveEscapes(true); assertTrue(sub.isPreserveEscapes()); assertEqualsCharSeq("value $${escaped}", replace(sub, org)); } } StringSubstitutorWithInterpolatorStringLookupTest.java000066400000000000000000000307151511432740600416170ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; import org.apache.commons.text.lookup.DefaultStringLookup; import org.apache.commons.text.lookup.StringLookup; import org.apache.commons.text.lookup.StringLookupFactory; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; class StringSubstitutorWithInterpolatorStringLookupTest { private static StringLookup createInterpolatorWithLookups(final DefaultStringLookup... lookups) { final Map lookupMap = new HashMap<>(); for (final DefaultStringLookup lookup : lookups) { lookupMap.put(lookup.getKey().toLowerCase(), lookup.getStringLookup()); } return StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); } @Test void testCustomFunctionWithDefaults() { testCustomFunctionWithDefaults(true); } private void testCustomFunctionWithDefaults(final boolean addDefaultLookups) { final String key = "key"; final String value = "value"; final Map map = new HashMap<>(); map.put(key, value); final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.functionStringLookup(map::get); final Map stringLookupMap = new HashMap<>(); stringLookupMap.put("customLookup", mapStringLookup); final StringSubstitutor strSubst = new StringSubstitutor( StringLookupFactory.INSTANCE.interpolatorStringLookup(stringLookupMap, null, addDefaultLookups)); if (addDefaultLookups) { final String spKey = "user.name"; Assertions.assertEquals(System.getProperty(spKey), strSubst.replace("${sys:" + spKey + "}")); } Assertions.assertEquals("value", strSubst.replace("${customLookup:key}")); } @Test void testCustomFunctionWithoutDefaults() { testCustomFunctionWithDefaults(false); } @Test void testCustomMapWithDefaults() { testCustomMapWithDefaults(true); } private void testCustomMapWithDefaults(final boolean addDefaultLookups) { final String key = "key"; final String value = "value"; final Map map = new HashMap<>(); map.put(key, value); final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.mapStringLookup(map); final Map stringLookupMap = new HashMap<>(); stringLookupMap.put("customLookup", mapStringLookup); final StringSubstitutor strSubst = new StringSubstitutor( StringLookupFactory.INSTANCE.interpolatorStringLookup(stringLookupMap, null, addDefaultLookups)); if (addDefaultLookups) { final String spKey = "user.name"; Assertions.assertEquals(System.getProperty(spKey), strSubst.replace("${sys:" + spKey + "}")); } Assertions.assertEquals("value", strSubst.replace("${customLookup:key}")); Assertions.assertEquals("${UnknownLookup:key}", strSubst.replace("${UnknownLookup:key}")); } @Test void testCustomMapWithoutDefaults() { testCustomMapWithDefaults(false); } @Test void testDefaultInterpolator() { // Used to cut and paste into the docs. // @formatter:off final StringSubstitutor interpolator = StringSubstitutor.createInterpolator(); final String text = interpolator.replace( "Base64 Decoder: ${base64Decoder:SGVsbG9Xb3JsZCE=}\n" + "Base64 Encoder: ${base64Encoder:HelloWorld!}\n" + "Java Constant: ${const:java.awt.event.KeyEvent.VK_ESCAPE}\n" + "Date: ${date:yyyy-MM-dd}\n" + "Environment Variable: ${env:USERNAME}\n" + "File Content: ${file:UTF-8:src/test/resources/org/apache/commons/text/document.properties}\n" + "Java: ${java:version}\n" + "Localhost: ${localhost:canonical-name}\n" + "Properties File: ${properties:src/test/resources/org/apache/commons/text/document.properties::mykey}\n" + "Resource Bundle: ${resourceBundle:org.apache.commons.text.example.testResourceBundleLookup:mykey}\n" + "System Property: ${sys:user.dir}\n" + "URL Decoder: ${urlDecoder:Hello%20World%21}\n" + "URL Encoder: ${urlEncoder:Hello World!}\n" + "XML XPath: ${xml:src/test/resources/org/apache/commons/text/document.xml:/root/path/to/node}\n" ); // @formatter:on Assertions.assertNotNull(text); // TEXT-171: Assertions.assertFalse(text.contains("${base64Decoder:SGVsbG9Xb3JsZCE=}")); Assertions.assertFalse(text.contains("${base64Encoder:HelloWorld!}")); Assertions.assertFalse(text.contains("${urlDecoder:Hello%20World%21}")); Assertions.assertFalse(text.contains("${urlEncoder:Hello World!}")); Assertions.assertFalse(text.contains("${resourceBundle:org.apache.commons.text.example.testResourceBundleLookup:mykey}")); } @Test void testDefaultValueForMissingKeyInResourceBundle() { final StringLookup interpolatorStringLookup = StringLookupFactory.INSTANCE.interpolatorStringLookup( StringLookupFactory.INSTANCE.resourceBundleStringLookup("org.apache.commons.text.example.testResourceBundleLookup")); assertEquals("${missingKey:-defaultValue}", interpolatorStringLookup.apply("keyWithMissingKey")); assertEquals("${missingKey:-defaultValue}", interpolatorStringLookup.lookup("keyWithMissingKey")); final StringSubstitutor stringSubstitutor = new StringSubstitutor(interpolatorStringLookup); // The following would throw a MissingResourceException before TEXT-165. assertEquals("defaultValue", stringSubstitutor.replace("${keyWithMissingKey}")); } @Test void testDnsLookup() throws UnknownHostException { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.DNS)); final String hostName = InetAddress.getLocalHost().getHostName(); Assertions.assertEquals(InetAddress.getByName(hostName).getHostAddress(), strSubst.replace("${dns:" + hostName + "}")); } @Test void testDnsLookup_disabledByDefault() throws UnknownHostException { final StringSubstitutor strSubst = StringSubstitutor.createInterpolator(); final String hostName = InetAddress.getLocalHost().getHostName(); final String input = "${dns:" + hostName + "}"; Assertions.assertEquals(input, strSubst.replace(input)); } @Test void testDnsLookupAddress() throws UnknownHostException { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.DNS)); Assertions.assertEquals(InetAddress.getByName("apache.org").getHostAddress(), strSubst.replace("${dns:address|apache.org}")); } @Test void testDnsLookupCanonicalName() throws UnknownHostException { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.DNS)); final String address = InetAddress.getLocalHost().getHostAddress(); final InetAddress inetAddress = InetAddress.getByName(address); Assertions.assertEquals(inetAddress.getCanonicalHostName(), strSubst.replace("${dns:canonical-name|" + address + "}")); } @Test void testDnsLookupName() throws UnknownHostException { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.DNS)); final String address = InetAddress.getLocalHost().getHostAddress(); final InetAddress inetAddress = InetAddress.getByName(address); Assertions.assertEquals(inetAddress.getHostName(), strSubst.replace("${dns:name|" + address + "}")); } @Test void testDnsLookupNameUntrimmed() throws UnknownHostException { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.DNS)); final String address = InetAddress.getLocalHost().getHostAddress(); final InetAddress inetAddress = InetAddress.getByName(address); Assertions.assertEquals(inetAddress.getHostName(), strSubst.replace("${dns:name| " + address + " }")); } @Test void testDnsLookupUnknown() { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.DNS)); final String unknown = "${dns: u n k n o w n}"; Assertions.assertEquals(unknown, strSubst.replace(unknown)); } @Test void testJavaScript() { final StringSubstitutor strSubst = new StringSubstitutor(createInterpolatorWithLookups(DefaultStringLookup.SCRIPT)); Assertions.assertEquals("Hello World!", strSubst.replace("${script:javascript:\"Hello World!\"}")); Assertions.assertEquals("7", strSubst.replace("${script:javascript:3 + 4}")); } @Test void testJavaScript_disabledByDefault() { final StringSubstitutor strSubst = StringSubstitutor.createInterpolator(); Assertions.assertEquals("${script:javascript:3 + 4}", strSubst.replace("${script:javascript:3 + 4}")); } @Test void testLocalHostLookup_Address() throws UnknownHostException { final StringSubstitutor strSubst = StringSubstitutor.createInterpolator(); Assertions.assertEquals(InetAddress.getLocalHost().getHostAddress(), strSubst.replace("${localhost:address}")); } @Test void testLocalHostLookup_CanonicalName() throws UnknownHostException { final StringSubstitutor strSubst = StringSubstitutor.createInterpolator(); Assertions.assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), strSubst.replace("${localhost:canonical-name}")); } @Test void testLocalHostLookup_Name() throws UnknownHostException { final StringSubstitutor strSubst = StringSubstitutor.createInterpolator(); Assertions.assertEquals(InetAddress.getLocalHost().getHostName(), strSubst.replace("${localhost:name}")); } @Test void testMapAndSystemProperty() { final String key = "key"; final String value = "value"; final Map map = new HashMap<>(); map.put(key, value); final StringSubstitutor strSubst = new StringSubstitutor( StringLookupFactory.INSTANCE.interpolatorStringLookup(map)); final String spKey = "user.name"; Assertions.assertEquals(System.getProperty(spKey), strSubst.replace("${sys:" + spKey + "}")); Assertions.assertEquals(value, strSubst.replace("${" + key + "}")); } @Test void testSystemProperty() { final StringSubstitutor strSubst = StringSubstitutor.createInterpolator(); final String spKey = "user.name"; Assertions.assertEquals(System.getProperty(spKey), strSubst.replace("${sys:" + spKey + "}")); } @Test void testSystemPropertyDefaultStringLookup() { final StringSubstitutor strSubst = new StringSubstitutor( StringLookupFactory.INSTANCE.interpolatorStringLookup(StringLookupFactory.INSTANCE.systemPropertyStringLookup())); final String spKey = "user.name"; Assertions.assertEquals(System.getProperty(spKey), strSubst.replace("${" + spKey + "}")); Assertions.assertEquals(System.getProperty(spKey), strSubst.replace("${sys:" + spKey + "}")); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/StringTokenizerTest.java000066400000000000000000001010411511432740600334500ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.text.matcher.StringMatcher; import org.apache.commons.text.matcher.StringMatcherFactory; import org.junit.jupiter.api.Test; /** * Unit test for {@link StringTokenizer}. */ class StringTokenizerTest { private static final String CSV_SIMPLE_FIXTURE = "A,b,c"; private static final String TSV_SIMPLE_FIXTURE = "A\tb\tc"; private void checkClone(final StringTokenizer tokenizer) { assertNotSame(StringTokenizer.getCSVInstance(), tokenizer); assertNotSame(StringTokenizer.getTSVInstance(), tokenizer); } @Test void test1() { final String input = "a;b;c;\"d;\"\"e\";f; ; ; "; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d;\"e", "f", "", "", "" }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test2() { final String input = "a;b;c ;\"d;\"\"e\";f; ; ;"; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.noneMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c ", "d;\"e", "f", " ", " ", "" }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test3() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.noneMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", " c", "d;\"e", "f", " ", " ", "" }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test4() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d;\"e", "f" }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test5() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d;\"e", "f", null, null, null }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test6() { final String input = "a;b; c;\"d;\"\"e\";f; ; ;"; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterChar(';'); tok.setQuoteChar('"'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); // tok.setTreatingEmptyAsNull(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", " c", "d;\"e", "f", null, null, null }; int nextCount = 0; while (tok.hasNext()) { tok.next(); nextCount++; } int prevCount = 0; while (tok.hasPrevious()) { tok.previous(); prevCount++; } assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); assertEquals(nextCount, expected.length, "could not cycle through entire token list using the 'hasNext' and 'next' methods"); assertEquals(prevCount, expected.length, "could not cycle through entire token list using the 'hasPrevious' and 'previous' methods"); } @Test void test7() { final String input = "a b c \"d e\" f "; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterMatcher(StringMatcherFactory.INSTANCE.spaceMatcher()); tok.setQuoteMatcher(StringMatcherFactory.INSTANCE.doubleQuoteMatcher()); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.noneMatcher()); tok.setIgnoreEmptyTokens(false); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "", "", "b", "c", "d e", "f", "" }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void test8() { final String input = "a b c \"d e\" f "; final StringTokenizer tok = new StringTokenizer(input); tok.setDelimiterMatcher(StringMatcherFactory.INSTANCE.spaceMatcher()); tok.setQuoteMatcher(StringMatcherFactory.INSTANCE.doubleQuoteMatcher()); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.noneMatcher()); tok.setIgnoreEmptyTokens(true); final String[] tokens = tok.getTokenArray(); final String[] expected = {"a", "b", "c", "d e", "f" }; assertEquals(expected.length, tokens.length, Arrays.toString(tokens)); for (int i = 0; i < expected.length; i++) { assertEquals(expected[i], tokens[i], "token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'"); } } @Test void testBasic1() { final String input = "a b c"; final StringTokenizer tok = new StringTokenizer(input); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic2() { final String input = "a \nb\fc"; final StringTokenizer tok = new StringTokenizer(input); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic3() { final String input = "a \nb\u0001\fc"; final StringTokenizer tok = new StringTokenizer(input); assertEquals("a", tok.next()); assertEquals("b\u0001", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic4() { final String input = "a \"b\" c"; final StringTokenizer tok = new StringTokenizer(input); assertEquals("a", tok.next()); assertEquals("\"b\"", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasic5() { final String input = "a:b':c"; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); assertEquals("a", tok.next()); assertEquals("b'", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicDelim1() { final String input = "a:b:c"; final StringTokenizer tok = new StringTokenizer(input, ':'); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicDelim2() { final String input = "a:b:c"; final StringTokenizer tok = new StringTokenizer(input, ','); assertEquals("a:b:c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicEmpty1() { final String input = "a b c"; final StringTokenizer tok = new StringTokenizer(input); tok.setIgnoreEmptyTokens(false); assertEquals("a", tok.next()); assertEquals("", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicEmpty2() { final String input = "a b c"; final StringTokenizer tok = new StringTokenizer(input); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertNull(tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed1() { final String input = "a: bIGNOREc : "; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE")); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bc", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed2() { final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE "; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE")); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bc", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed3() { final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE "; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE")); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals(" bc ", tok.next()); assertEquals(" ", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicIgnoreTrimmed4() { final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE "; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE")); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bIGNOREcd", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted1() { final String input = "a 'b' c"; final StringTokenizer tok = new StringTokenizer(input, ' ', '\''); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted2() { final String input = "a:'b':"; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted3() { final String input = "a:'b''c'"; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b'c", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted4() { final String input = "a: 'b' 'c' :d"; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b c", tok.next()); assertEquals("d", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted5() { final String input = "a: 'b'x'c' :d"; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("bxc", tok.next()); assertEquals("d", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted6() { final String input = "a:'b'\"c':d"; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setQuoteMatcher(StringMatcherFactory.INSTANCE.quoteMatcher()); assertEquals("a", tok.next()); assertEquals("b\"c:d", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuoted7() { final String input = "a:\"There's a reason here\":b"; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setQuoteMatcher(StringMatcherFactory.INSTANCE.quoteMatcher()); assertEquals("a", tok.next()); assertEquals("There's a reason here", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicQuotedTrimmed1() { final String input = "a: 'b' :"; final StringTokenizer tok = new StringTokenizer(input, ':', '\''); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicTrimmed1() { final String input = "a: b : "; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher()); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testBasicTrimmed2() { final String input = "a: b :"; final StringTokenizer tok = new StringTokenizer(input, ':'); tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.stringMatcher(" ")); tok.setIgnoreEmptyTokens(false); tok.setEmptyTokenAsNull(true); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertNull(tok.next()); assertFalse(tok.hasNext()); } @Test void testChaining() { final StringTokenizer tok = new StringTokenizer(); assertEquals(tok, tok.reset()); assertEquals(tok, tok.reset("")); assertEquals(tok, tok.reset(ArrayUtils.EMPTY_CHAR_ARRAY)); assertEquals(tok, tok.setDelimiterChar(' ')); assertEquals(tok, tok.setDelimiterString(" ")); assertEquals(tok, tok.setDelimiterMatcher(null)); assertEquals(tok, tok.setQuoteChar(' ')); assertEquals(tok, tok.setQuoteMatcher(null)); assertEquals(tok, tok.setIgnoredChar(' ')); assertEquals(tok, tok.setIgnoredMatcher(null)); assertEquals(tok, tok.setTrimmerMatcher(null)); assertEquals(tok, tok.setEmptyTokenAsNull(false)); assertEquals(tok, tok.setIgnoreEmptyTokens(false)); } /** * Tests that the {@link StringTokenizer#clone()} clone method catches {@link CloneNotSupportedException} and * returns {@code null}. */ @Test void testCloneNotSupportedException() { final Object notCloned = new StringTokenizer() { @Override Object cloneReset() throws CloneNotSupportedException { throw new CloneNotSupportedException("test"); } }.clone(); assertNull(notCloned); } @Test void testCloneNull() { final StringTokenizer tokenizer = new StringTokenizer((char[]) null); // Start sanity check assertNull(tokenizer.nextToken()); tokenizer.reset(); assertNull(tokenizer.nextToken()); // End sanity check final StringTokenizer clonedTokenizer = (StringTokenizer) tokenizer.clone(); tokenizer.reset(); assertNull(tokenizer.nextToken()); assertNull(clonedTokenizer.nextToken()); } @Test void testCloneReset() { final char[] input = { 'a' }; final StringTokenizer tokenizer = new StringTokenizer(input); // Start sanity check assertEquals("a", tokenizer.nextToken()); tokenizer.reset(input); assertEquals("a", tokenizer.nextToken()); // End sanity check final StringTokenizer clonedTokenizer = (StringTokenizer) tokenizer.clone(); input[0] = 'b'; tokenizer.reset(input); assertEquals("b", tokenizer.nextToken()); assertEquals("a", clonedTokenizer.nextToken()); } @Test void testConstructor_charArray() { StringTokenizer tok = new StringTokenizer("a b".toCharArray()); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY); assertFalse(tok.hasNext()); tok = new StringTokenizer((char[]) null); assertFalse(tok.hasNext()); } @Test void testConstructor_charArray_char() { StringTokenizer tok = new StringTokenizer("a b".toCharArray(), ' '); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' '); assertFalse(tok.hasNext()); tok = new StringTokenizer((char[]) null, ' '); assertFalse(tok.hasNext()); } @Test void testConstructor_charArray_char_char() { StringTokenizer tok = new StringTokenizer("a b".toCharArray(), ' ', '"'); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1)); assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getQuoteMatcher().isMatch("\"", 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"'); assertFalse(tok.hasNext()); tok = new StringTokenizer((char[]) null, ' ', '"'); assertFalse(tok.hasNext()); } @Test void testConstructor_String() { StringTokenizer tok = new StringTokenizer("a b"); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StringTokenizer(""); assertFalse(tok.hasNext()); tok = new StringTokenizer((String) null); assertFalse(tok.hasNext()); } @Test void testConstructor_String_char() { StringTokenizer tok = new StringTokenizer("a b", ' '); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StringTokenizer("", ' '); assertFalse(tok.hasNext()); tok = new StringTokenizer((String) null, ' '); assertFalse(tok.hasNext()); } @Test void testConstructor_String_char_char() { StringTokenizer tok = new StringTokenizer("a b", ' ', '"'); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1)); assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1)); assertEquals(1, tok.getQuoteMatcher().isMatch("\"", 0, 0, 1)); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertFalse(tok.hasNext()); tok = new StringTokenizer("", ' ', '"'); assertFalse(tok.hasNext()); tok = new StringTokenizer((String) null, ' ', '"'); assertFalse(tok.hasNext()); } private void testCSV(final String data) { testXSVAbc(StringTokenizer.getCSVInstance(data)); testXSVAbc(StringTokenizer.getCSVInstance(data.toCharArray())); } @Test void testCSVEmpty() { testEmpty(StringTokenizer.getCSVInstance()); testEmpty(StringTokenizer.getCSVInstance("")); } @Test void testCSVSimple() { testCSV(CSV_SIMPLE_FIXTURE); } @Test void testCSVSimpleNeedsTrim() { testCSV(" " + CSV_SIMPLE_FIXTURE); testCSV(" \n\t " + CSV_SIMPLE_FIXTURE); testCSV(" \n " + CSV_SIMPLE_FIXTURE + "\n\n\r"); } @Test void testDelimMatcher() { final String input = "a/b\\c"; final StringMatcher delimMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('/', '\\'); final StringTokenizer tok = new StringTokenizer(input, delimMatcher); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testDelimMatcherQuoteMatcher() { final String input = "`a`;`b`;`c`"; final StringMatcher delimMatcher = StringMatcherFactory.INSTANCE.charSetMatcher(';'); final StringMatcher quoteMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('`'); final StringTokenizer tok = new StringTokenizer(input, delimMatcher, quoteMatcher); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testDelimString() { final String input = "a##b##c"; final StringTokenizer tok = new StringTokenizer(input, "##"); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } void testEmpty(final StringTokenizer tokenizer) { checkClone(tokenizer); assertFalse(tokenizer.hasNext()); assertFalse(tokenizer.hasPrevious()); assertNull(tokenizer.nextToken()); assertEquals(0, tokenizer.size()); assertThrows(NoSuchElementException.class, tokenizer::next); } @Test void testGetContent() { final String input = "a b c \"d e\" f "; StringTokenizer tok = new StringTokenizer(input); assertEquals(input, tok.getContent()); tok = new StringTokenizer(input.toCharArray()); assertEquals(input, tok.getContent()); tok = new StringTokenizer(); assertNull(tok.getContent()); } @Test void testIteration() { final StringTokenizer tkn = new StringTokenizer("a b c"); assertFalse(tkn.hasPrevious()); assertThrows(NoSuchElementException.class, tkn::previous); assertTrue(tkn.hasNext()); assertEquals("a", tkn.next()); assertThrows(UnsupportedOperationException.class, tkn::remove); assertThrows(UnsupportedOperationException.class, () -> tkn.set("x")); assertThrows(UnsupportedOperationException.class, () -> tkn.add("y")); assertTrue(tkn.hasPrevious()); assertTrue(tkn.hasNext()); assertEquals("b", tkn.next()); assertTrue(tkn.hasPrevious()); assertTrue(tkn.hasNext()); assertEquals("c", tkn.next()); assertTrue(tkn.hasPrevious()); assertFalse(tkn.hasNext()); assertThrows(NoSuchElementException.class, tkn::next); assertTrue(tkn.hasPrevious()); assertFalse(tkn.hasNext()); } @Test void testListArray() { final String input = "a b c"; final StringTokenizer tok = new StringTokenizer(input); final String[] array = tok.getTokenArray(); final List list = tok.getTokenList(); assertEquals(Arrays.asList(array), list); assertEquals(3, list.size()); // Test modification of the returned list list.set(0, "z"); list.remove(1); list.set(1, "y"); list.add("x"); assertEquals(Arrays.asList("z", "y", "x"), list); // The tokenizer is unchanged assertEquals(Arrays.asList(array), tok.getTokenList()); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); } @Test void testPreviousTokenAndSetEmptyTokenAsNull() { final StringTokenizer strTokenizer = StringTokenizer.getTSVInstance(" \t\n\r\f"); strTokenizer.setEmptyTokenAsNull(true); assertNull(strTokenizer.previousToken()); } @Test void testReset() { final StringTokenizer tok = new StringTokenizer("a b c"); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); tok.reset(); assertEquals("a", tok.next()); assertEquals("b", tok.next()); assertEquals("c", tok.next()); assertFalse(tok.hasNext()); } @Test void testReset_charArray() { final StringTokenizer tok = new StringTokenizer("x x x"); final char[] array = {'a', 'b', 'c' }; tok.reset(array); assertEquals("abc", tok.next()); assertFalse(tok.hasNext()); tok.reset((char[]) null); assertFalse(tok.hasNext()); } @Test void testReset_String() { final StringTokenizer tok = new StringTokenizer("x x x"); tok.reset("d e"); assertEquals("d", tok.next()); assertEquals("e", tok.next()); assertFalse(tok.hasNext()); tok.reset((String) null); assertFalse(tok.hasNext()); } @Test void testStringTokenizerQuoteMatcher() { final char[] chars = {'\'', 'a', 'c', '\'', 'd' }; final StringTokenizer tokens = new StringTokenizer(chars, StringMatcherFactory.INSTANCE.commaMatcher(), StringMatcherFactory.INSTANCE.quoteMatcher()); assertEquals("acd", tokens.next()); } @Test void testStringTokenizerStringMatcher() { final char[] chars = {'a', 'b', 'c', 'd' }; final StringTokenizer tokens = new StringTokenizer(chars, "bc"); assertEquals("a", tokens.next()); assertEquals("d", tokens.next()); } @Test void testStringTokenizerStrMatcher() { final char[] chars = {'a', ',', 'c' }; final StringTokenizer tokens = new StringTokenizer(chars, StringMatcherFactory.INSTANCE.commaMatcher()); assertEquals("a", tokens.next()); assertEquals("c", tokens.next()); } @Test void testTokenizeSubclassInputChange() { final StringTokenizer tkn = new StringTokenizer("a b c d e") { @Override protected List tokenize(final char[] chars, final int offset, final int count) { return super.tokenize("w x y z".toCharArray(), 2, 5); } }; assertEquals("x", tkn.next()); assertEquals("y", tkn.next()); } @Test void testTokenizeSubclassOutputChange() { final StringTokenizer tkn = new StringTokenizer("a b c") { @Override protected List tokenize(final char[] chars, final int offset, final int count) { final List list = super.tokenize(chars, offset, count); Collections.reverse(list); return list; } }; assertEquals("c", tkn.next()); assertEquals("b", tkn.next()); assertEquals("a", tkn.next()); } @Test void testToString() { final StringTokenizer tkn = new StringTokenizer("a b c d e"); assertEquals("StringTokenizer[not tokenized yet]", tkn.toString()); tkn.next(); assertEquals("StringTokenizer[a, b, c, d, e]", tkn.toString()); } @Test void testTSV() { testXSVAbc(StringTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE)); testXSVAbc(StringTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray())); } @Test void testTSVEmpty() { testEmpty(StringTokenizer.getTSVInstance()); testEmpty(StringTokenizer.getTSVInstance("")); } void testXSVAbc(final StringTokenizer tokenizer) { checkClone(tokenizer); assertEquals(-1, tokenizer.previousIndex()); assertEquals(0, tokenizer.nextIndex()); assertNull(tokenizer.previousToken()); assertEquals("A", tokenizer.nextToken()); assertEquals(1, tokenizer.nextIndex()); assertEquals("b", tokenizer.nextToken()); assertEquals(2, tokenizer.nextIndex()); assertEquals("c", tokenizer.nextToken()); assertEquals(3, tokenizer.nextIndex()); assertNull(tokenizer.nextToken()); assertEquals(3, tokenizer.nextIndex()); assertEquals("c", tokenizer.previousToken()); assertEquals(2, tokenizer.nextIndex()); assertEquals("b", tokenizer.previousToken()); assertEquals(1, tokenizer.nextIndex()); assertEquals("A", tokenizer.previousToken()); assertEquals(0, tokenizer.nextIndex()); assertNull(tokenizer.previousToken()); assertEquals(0, tokenizer.nextIndex()); assertEquals(-1, tokenizer.previousIndex()); assertEquals(3, tokenizer.size()); } } TextStringBuilderAppendInsertTest.java000066400000000000000000001256451511432740600362070ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.text.DecimalFormatSymbols; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.Test; /** * Tests {@link TextStringBuilder}. */ class TextStringBuilderAppendInsertTest { /** The system line separator. */ private static final String SEP = System.lineSeparator(); /** Test subclass of Object, with a toString method. */ private static final Object FOO = new Object() { @Override public String toString() { return "foo"; } }; @Test void testAppend_Boolean() { final TextStringBuilder sb = new TextStringBuilder(); sb.append(true); assertEquals("true", sb.toString()); sb.append(false); assertEquals("truefalse", sb.toString()); sb.append('!'); assertEquals("truefalse!", sb.toString()); } @Test void testAppend_CharArray() { TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("NULL").append((char[]) null); assertEquals("NULL", sb.toString()); sb = new TextStringBuilder(); sb.append(ArrayUtils.EMPTY_CHAR_ARRAY); assertEquals("", sb.toString()); sb.append(new char[] {'f', 'o', 'o'}); assertEquals("foo", sb.toString()); } @Test void testAppend_CharArray_int_int() { final TextStringBuilder sb0 = new TextStringBuilder(); sb0.setNullText("NULL").append((char[]) null, 0, 1); assertEquals("NULL", sb0.toString()); final TextStringBuilder sb = new TextStringBuilder(); sb.append(new char[] {'f', 'o', 'o'}, 0, 3); assertEquals("foo", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new char[] {'b', 'a', 'r'}, -1, 1), "append(char[], -1,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new char[] {'b', 'a', 'r'}, 3, 1), "append(char[], 3,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new char[] {'b', 'a', 'r'}, 1, -1), "append(char[],, -1) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new char[] {'b', 'a', 'r'}, 1, 3), "append(char[], 1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new char[] {'b', 'a', 'r'}, -1, 3), "append(char[], -1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new char[] {'b', 'a', 'r'}, 4, 0), "append(char[], 4, 0) expected IndexOutOfBoundsException"); sb.append(new char[] {'b', 'a', 'r'}, 3, 0); assertEquals("foo", sb.toString()); sb.append(new char[] {'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 3); assertEquals("foobar", sb.toString()); } @Test void testAppend_FormattedString() { TextStringBuilder sb; sb = new TextStringBuilder(); sb.append("Hi", (Object[]) null); assertEquals("Hi", sb.toString()); sb = new TextStringBuilder(); sb.append("Hi", "Alice"); assertEquals("Hi", sb.toString()); sb = new TextStringBuilder(); sb.append("Hi %s", "Alice"); assertEquals("Hi Alice", sb.toString()); sb = new TextStringBuilder(); sb.append("Hi %s %,d", "Alice", 5000); // group separator depends on system locale final char groupingSeparator = DecimalFormatSymbols.getInstance().getGroupingSeparator(); final String expected = "Hi Alice 5" + groupingSeparator + "000"; assertEquals(expected, sb.toString()); } @Test void testAppend_Object() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendNull(); assertEquals("", sb.toString()); sb.append((Object) null); assertEquals("", sb.toString()); sb.append(FOO); assertEquals("foo", sb.toString()); sb.append((StringBuffer) null); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("baz")); assertEquals("foobaz", sb.toString()); sb.append(new TextStringBuilder("yes")); assertEquals("foobazyes", sb.toString()); sb.append((CharSequence) "Seq"); assertEquals("foobazyesSeq", sb.toString()); sb.append(new StringBuilder("bld")); // Check it supports StringBuilder assertEquals("foobazyesSeqbld", sb.toString()); } @Test void testAppend_PrimitiveNumber() { final TextStringBuilder sb = new TextStringBuilder(); sb.append(0); assertEquals("0", sb.toString()); sb.append(1L); assertEquals("01", sb.toString()); sb.append(2.3f); assertEquals("012.3", sb.toString()); sb.append(4.5d); assertEquals("012.34.5", sb.toString()); } @Test void testAppend_String() { TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("NULL").append((String) null); assertEquals("NULL", sb.toString()); sb = new TextStringBuilder(); sb.append("foo"); assertEquals("foo", sb.toString()); sb.append(""); assertEquals("foo", sb.toString()); sb.append("bar"); assertEquals("foobar", sb.toString()); } @Test void testAppend_String_int_int() { final TextStringBuilder sb0 = new TextStringBuilder(); sb0.setNullText("NULL").append((String) null, 0, 1); assertEquals("NULL", sb0.toString()); final TextStringBuilder sb = new TextStringBuilder(); sb.append("foo", 0, 3); assertEquals("foo", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.append("bar", -1, 1), "append(char[], -1,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append("bar", 3, 1), "append(char[], 3,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append("bar", 1, -1), "append(char[],, -1) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append("bar", 1, 3), "append(char[], 1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append("bar", -1, 3), "append(char[], -1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append("bar", 4, 0), "append(char[], 4, 0) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append((CharSequence) "bar", 2, 1), "append(char[], 2, 1) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append((CharSequence) "bar", 2, 2), "append(char[], 2, 2) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append((CharSequence) "bar", 2, -2), "append(char[], 2, -2) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append((CharSequence) "bar", 2, 0), "append(char[], 2, 0) expected IndexOutOfBoundsException"); sb.append("bar", 3, 0); assertEquals("foo", sb.toString()); sb.append("abcbardef", 3, 3); assertEquals("foobar", sb.toString()); sb.append((CharSequence) "abcbardef", 4, 7); assertEquals("foobarard", sb.toString()); } @Test void testAppend_StringBuffer() { TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("NULL").append((StringBuffer) null); assertEquals("NULL", sb.toString()); sb = new TextStringBuilder(); sb.append(new StringBuffer("foo")); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("")); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("bar")); assertEquals("foobar", sb.toString()); } @Test void testAppend_StringBuffer_int_int() { final TextStringBuilder sb0 = new TextStringBuilder(); sb0.setNullText("NULL").append((StringBuffer) null, 0, 1); assertEquals("NULL", sb0.toString()); final TextStringBuilder sb = new TextStringBuilder(); sb.append(new StringBuffer("foo"), 0, 3); assertEquals("foo", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuffer("bar"), -1, 1), "append(char[], -1,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuffer("bar"), 3, 1), "append(char[], 3,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuffer("bar"), 1, -1), "append(char[],, -1) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuffer("bar"), 1, 3), "append(char[], 1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuffer("bar"), -1, 3), "append(char[], -1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuffer("bar"), 4, 0), "append(char[], 4, 0) expected IndexOutOfBoundsException"); sb.append(new StringBuffer("bar"), 3, 0); assertEquals("foo", sb.toString()); sb.append(new StringBuffer("abcbardef"), 3, 3); assertEquals("foobar", sb.toString()); } @Test void testAppend_StringBuilder() { TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("NULL").append((String) null); assertEquals("NULL", sb.toString()); sb = new TextStringBuilder(); sb.append(new StringBuilder("foo")); assertEquals("foo", sb.toString()); sb.append(new StringBuilder("")); assertEquals("foo", sb.toString()); sb.append(new StringBuilder("bar")); assertEquals("foobar", sb.toString()); } @Test void testAppend_StringBuilder_int_int() { final TextStringBuilder sb0 = new TextStringBuilder(); sb0.setNullText("NULL").append((String) null, 0, 1); assertEquals("NULL", sb0.toString()); final TextStringBuilder sb = new TextStringBuilder(); sb.append(new StringBuilder("foo"), 0, 3); assertEquals("foo", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuilder("bar"), -1, 1), "append(StringBuilder, -1,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuilder("bar"), 3, 1), "append(StringBuilder, 3,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuilder("bar"), 1, -1), "append(StringBuilder,, -1) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuilder("bar"), 1, 3), "append(StringBuilder, 1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuilder("bar"), -1, 3), "append(StringBuilder, -1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new StringBuilder("bar"), 4, 0), "append(StringBuilder, 4, 0) expected IndexOutOfBoundsException"); sb.append(new StringBuilder("bar"), 3, 0); assertEquals("foo", sb.toString()); sb.append(new StringBuilder("abcbardef"), 3, 3); assertEquals("foobar", sb.toString()); sb.append(new StringBuilder("abcbardef"), 4, 3); assertEquals("foobarard", sb.toString()); } @Test void testAppend_TextStringBuilder() { TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("NULL").append((TextStringBuilder) null); assertEquals("NULL", sb.toString()); sb = new TextStringBuilder(); sb.append(new TextStringBuilder("foo")); assertEquals("foo", sb.toString()); sb.append(new TextStringBuilder("")); assertEquals("foo", sb.toString()); sb.append(new TextStringBuilder("bar")); assertEquals("foobar", sb.toString()); } @Test void testAppend_TextStringBuilder_int_int() { final TextStringBuilder sb0 = new TextStringBuilder(); sb0.setNullText("NULL").append((TextStringBuilder) null, 0, 1); assertEquals("NULL", sb0.toString()); final TextStringBuilder sb = new TextStringBuilder(); sb.append(new TextStringBuilder("foo"), 0, 3); assertEquals("foo", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new TextStringBuilder("bar"), -1, 1), "append(char[], -1,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new TextStringBuilder("bar"), 3, 1), "append(char[], 3,) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new TextStringBuilder("bar"), 1, -1), "append(char[],, -1) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new TextStringBuilder("bar"), 1, 3), "append(char[], 1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new TextStringBuilder("bar"), -1, 3), "append(char[], -1, 3) expected IndexOutOfBoundsException"); assertThrows(IndexOutOfBoundsException.class, () -> sb.append(new TextStringBuilder("bar"), 4, 0), "append(char[], 4, 0) expected IndexOutOfBoundsException"); sb.append(new TextStringBuilder("bar"), 3, 0); assertEquals("foo", sb.toString()); sb.append(new TextStringBuilder("abcbardef"), 3, 3); assertEquals("foobar", sb.toString()); } @Test void testAppendAll_Array() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendAll((Object[]) null); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(); assertEquals("", sb.toString()); sb.clear(); sb.appendAll("foo", "bar", "baz"); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendAll("foo", "bar", "baz"); assertEquals("foobarbaz", sb.toString()); } @Test void testAppendAll_Collection() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendAll((Collection) null); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Collections.EMPTY_LIST); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Arrays.asList("foo", "bar", "baz")); assertEquals("foobarbaz", sb.toString()); } @Test void testAppendAll_Iterator() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendAll((Iterator) null); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Collections.EMPTY_LIST.iterator()); assertEquals("", sb.toString()); sb.clear(); sb.appendAll(Arrays.asList("foo", "bar", "baz").iterator()); assertEquals("foobarbaz", sb.toString()); } @Test void testAppendFixedWidthPadLeft() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendFixedWidthPadLeft("foo", -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 1, '-'); assertEquals("o", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 2, '-'); assertEquals("oo", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 3, '-'); assertEquals("foo", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 4, '-'); assertEquals("-foo", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft("foo", 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("-------foo", sb.toString()); sb.clear(); sb.setNullText("null"); sb.appendFixedWidthPadLeft(null, 5, '-'); assertEquals("-null", sb.toString()); } @Test void testAppendFixedWidthPadLeft_int() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendFixedWidthPadLeft(123, -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 1, '-'); assertEquals("3", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 2, '-'); assertEquals("23", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 3, '-'); assertEquals("123", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 4, '-'); assertEquals("-123", sb.toString()); sb.clear(); sb.appendFixedWidthPadLeft(123, 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("-------123", sb.toString()); } @Test void testAppendFixedWidthPadRight() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendFixedWidthPadRight("foo", -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 1, '-'); assertEquals("f", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 2, '-'); assertEquals("fo", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 3, '-'); assertEquals("foo", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 4, '-'); assertEquals("foo-", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight("foo", 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("foo-------", sb.toString()); sb.clear(); sb.setNullText("null"); sb.appendFixedWidthPadRight(null, 5, '-'); assertEquals("null-", sb.toString()); } @Test void testAppendFixedWidthPadRight_int() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendFixedWidthPadRight(123, -1, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 0, '-'); assertEquals("", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 1, '-'); assertEquals("1", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 2, '-'); assertEquals("12", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 3, '-'); assertEquals("123", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 4, '-'); assertEquals("123-", sb.toString()); sb.clear(); sb.appendFixedWidthPadRight(123, 10, '-'); assertEquals(10, sb.length()); // 1234567890 assertEquals("123-------", sb.toString()); } @Test void testAppendln_Boolean() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendln(true); assertEquals("true" + SEP, sb.toString()); sb.clear(); sb.appendln(false); assertEquals("false" + SEP, sb.toString()); } @Test void testAppendln_CharArray() { final TextStringBuilder sb = spy(new TextStringBuilder()); final char[] input = "foo".toCharArray(); sb.appendln(input); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(input); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_CharArray_int_int() { final TextStringBuilder sb = spy(new TextStringBuilder()); final char[] input = "foo".toCharArray(); sb.appendln(input, 0, 3); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(input, 0, 3); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_FormattedString() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln("Hello %s", "Alice"); assertEquals("Hello Alice" + SEP, sb.toString()); verify(sb, times(2)).append(anyString()); // appendNewLine() calls append(String) verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_Object() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendln((Object) null); assertEquals("" + SEP, sb.toString()); sb.appendln(FOO); assertEquals(SEP + "foo" + SEP, sb.toString()); sb.appendln(Integer.valueOf(6)); assertEquals(SEP + "foo" + SEP + "6" + SEP, sb.toString()); } @Test void testAppendln_PrimitiveNumber() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendln(0); assertEquals("0" + SEP, sb.toString()); sb.clear(); sb.appendln(1L); assertEquals("1" + SEP, sb.toString()); sb.clear(); sb.appendln(2.3f); assertEquals("2.3" + SEP, sb.toString()); sb.clear(); sb.appendln(4.5d); assertEquals("4.5" + SEP, sb.toString()); } @Test void testAppendln_String() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln("foo"); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(2)).append(anyString()); // appendNewLine() calls append(String) verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_String_int_int() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln("foo", 0, 3); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(2)).append(anyString(), anyInt(), anyInt()); // appendNewLine() calls append(String) verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_StringBuffer() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln(new StringBuffer("foo")); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(any(StringBuffer.class)); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_StringBuffer_int_int() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln(new StringBuffer("foo"), 0, 3); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(any(StringBuffer.class), anyInt(), anyInt()); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_StringBuilder() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln(new StringBuilder("foo")); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(any(StringBuilder.class)); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_StringBuilder_int_int() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln(new StringBuilder("foo"), 0, 3); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(any(StringBuilder.class), anyInt(), anyInt()); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_TextStringBuilder() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln(new TextStringBuilder("foo")); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(any(TextStringBuilder.class)); verify(sb, times(1)).appendNewLine(); } @Test void testAppendln_TextStringBuilder_int_int() { final TextStringBuilder sb = spy(new TextStringBuilder()); sb.appendln(new TextStringBuilder("foo"), 0, 3); assertEquals("foo" + SEP, sb.toString()); verify(sb, times(1)).append(any(TextStringBuilder.class), anyInt(), anyInt()); verify(sb, times(1)).appendNewLine(); } @Test void testAppendNewLine() { TextStringBuilder sb = new TextStringBuilder("---"); sb.appendNewLine().append("+++"); assertEquals("---" + SEP + "+++", sb.toString()); sb = new TextStringBuilder("---"); sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine(); assertEquals("---#" + SEP, sb.toString()); } @Test void testAppendPadding() { final TextStringBuilder sb = new TextStringBuilder(); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendPadding(-1, '-'); assertEquals("foo", sb.toString()); sb.appendPadding(0, '-'); assertEquals("foo", sb.toString()); sb.appendPadding(1, '-'); assertEquals("foo-", sb.toString()); sb.appendPadding(16, '-'); assertEquals(20, sb.length()); // 12345678901234567890 assertEquals("foo-----------------", sb.toString()); } @Test void testAppendSeparator_char() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendSeparator(','); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(','); assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_char_char() { final TextStringBuilder sb = new TextStringBuilder(); final char startSeparator = ':'; final char standardSeparator = ','; final String foo = "foo"; sb.appendSeparator(standardSeparator, startSeparator); // no effect assertEquals(String.valueOf(startSeparator), sb.toString()); sb.append(foo); assertEquals(String.valueOf(startSeparator) + foo, sb.toString()); sb.appendSeparator(standardSeparator, startSeparator); assertEquals(String.valueOf(startSeparator) + foo + standardSeparator, sb.toString()); } @Test void testAppendSeparator_char_int() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendSeparator(',', 0); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(',', 1); assertEquals("foo,", sb.toString()); sb.appendSeparator(',', -1); // no effect assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_String() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendSeparator(","); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(","); assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_String_int() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendSeparator(null, -1); // no effect assertEquals("", sb.toString()); sb.appendSeparator(null, 0); // no effect assertEquals("", sb.toString()); sb.appendSeparator(null, 1); // no effect assertEquals("", sb.toString()); sb.appendSeparator(",", -1); // no effect assertEquals("", sb.toString()); sb.appendSeparator(",", 0); // no effect assertEquals("", sb.toString()); sb.append("foo"); assertEquals("foo", sb.toString()); sb.appendSeparator(",", 1); assertEquals("foo,", sb.toString()); sb.appendSeparator(",", -1); // no effect assertEquals("foo,", sb.toString()); } @Test void testAppendSeparator_String_String() { final TextStringBuilder sb = new TextStringBuilder(); final String startSeparator = "order by "; final String standardSeparator = ","; final String foo = "foo"; sb.appendSeparator(null, null); assertEquals("", sb.toString()); sb.appendSeparator(standardSeparator, null); assertEquals("", sb.toString()); sb.appendSeparator(standardSeparator, startSeparator); assertEquals(startSeparator, sb.toString()); sb.appendSeparator(null, null); assertEquals(startSeparator, sb.toString()); sb.appendSeparator(null, startSeparator); assertEquals(startSeparator, sb.toString()); sb.append(foo); assertEquals(startSeparator + foo, sb.toString()); sb.appendSeparator(standardSeparator, startSeparator); assertEquals(startSeparator + foo + standardSeparator, sb.toString()); } @Test void testAppendWithNullText() { final TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("NULL"); assertEquals("", sb.toString()); sb.appendNull(); assertEquals("NULL", sb.toString()); sb.append((Object) null); assertEquals("NULLNULL", sb.toString()); sb.append(FOO); assertEquals("NULLNULLfoo", sb.toString()); sb.append((String) null); assertEquals("NULLNULLfooNULL", sb.toString()); sb.append(""); assertEquals("NULLNULLfooNULL", sb.toString()); sb.append("bar"); assertEquals("NULLNULLfooNULLbar", sb.toString()); sb.append((StringBuffer) null); assertEquals("NULLNULLfooNULLbarNULL", sb.toString()); sb.append(new StringBuffer("baz")); assertEquals("NULLNULLfooNULLbarNULLbaz", sb.toString()); } @Test void testAppendWithSeparators_Array() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendWithSeparators((Object[]) null, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(ArrayUtils.EMPTY_OBJECT_ARRAY, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(new Object[] {"foo", "bar", "baz"}, ","); assertEquals("foo,bar,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(new Object[] {"foo", "bar", "baz"}, null); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendWithSeparators(new Object[] {"foo", null, "baz"}, ","); assertEquals("foo,,baz", sb.toString()); } @Test void testAppendWithSeparators_Collection() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendWithSeparators((Collection) null, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Collections.EMPTY_LIST, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz"), ","); assertEquals("foo,bar,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz"), null); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", null, "baz"), ","); assertEquals("foo,,baz", sb.toString()); } @Test void testAppendWithSeparators_Iterator() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendWithSeparators((Iterator) null, ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Collections.EMPTY_LIST.iterator(), ","); assertEquals("", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz").iterator(), ","); assertEquals("foo,bar,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", "bar", "baz").iterator(), null); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", null, "baz").iterator(), ","); assertEquals("foo,,baz", sb.toString()); } @Test void testAppendWithSeparatorsWithNullText() { final TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("null"); sb.appendWithSeparators(new Object[] {"foo", null, "baz"}, ","); assertEquals("foo,null,baz", sb.toString()); sb.clear(); sb.appendWithSeparators(Arrays.asList("foo", null, "baz"), ","); assertEquals("foo,null,baz", sb.toString()); } @Test void testInsert() { final TextStringBuilder sb = new TextStringBuilder(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, FOO)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, FOO)); sb.insert(0, (Object) null); assertEquals("barbaz", sb.toString()); sb.insert(0, FOO); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, "foo")); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, "foo")); sb.insert(0, (String) null); assertEquals("barbaz", sb.toString()); sb.insert(0, "foo"); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, new char[] {'f', 'o', 'o'})); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, new char[] {'f', 'o', 'o'})); sb.insert(0, (char[]) null); assertEquals("barbaz", sb.toString()); sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY); assertEquals("barbaz", sb.toString()); sb.insert(0, new char[] {'f', 'o', 'o'}); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3)); sb.insert(0, (char[]) null, 0, 0); assertEquals("barbaz", sb.toString()); sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY, 0, 0); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, -1, 3)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 10, 3)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, -1)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(0, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 10)); sb.insert(0, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 0); assertEquals("barbaz", sb.toString()); sb.insert(0, new char[] {'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3); assertEquals("foobarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, true)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, true)); sb.insert(0, true); assertEquals("truebarbaz", sb.toString()); sb.insert(0, false); assertEquals("falsetruebarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, '!')); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, '!')); sb.insert(0, '!'); assertEquals("!barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 0)); sb.insert(0, '0'); assertEquals("0barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 1L)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 1L)); sb.insert(0, 1L); assertEquals("1barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 2.3F)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 2.3F)); sb.insert(0, 2.3F); assertEquals("2.3barbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 4.5D)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, 4.5D)); sb.insert(0, 4.5D); assertEquals("4.5barbaz", sb.toString()); } @Test void testInsertAtEnd() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals("", sb.toString()); sb.insert(0, "Hello"); assertEquals("Hello", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, "World")); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(6, "World")); sb.insert(5, true); assertEquals("Hellotrue", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(10, false)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-20, false)); sb.insert(9, 'A'); assertEquals("HellotrueA", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(11, 'B')); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-2, 'B')); sb.insert(10, new char[] { 'B', 'C' }); assertEquals("HellotrueABC", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(13, new char[] { 'D', 'E' })); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, new char[] { 'D', 'E' })); sb.insert(12, new char[] { 'D', 'E', 'F' }, 1, 1); assertEquals("HellotrueABCE", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(14, new char[] { 'G', 'H', 'I' }, 1, 2)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, new char[] { 'G', 'H', 'I' }, 1, 1)); sb.insert(13, 1.2d); assertEquals("HellotrueABCE1.2", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(17, 1.3d)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, 1.3d)); sb.insert(16, 1f); assertEquals("HellotrueABCE1.21.0", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(20, 1.3f)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-3, 1.3f)); sb.insert(19, 23); assertEquals("HellotrueABCE1.21.023", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(22, 20)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-5, -5)); sb.insert(21, 99L); assertEquals("HellotrueABCE1.21.02399", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(24, 22L)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, -1L)); sb.insert(23, FOO); assertEquals("HellotrueABCE1.21.02399foo", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(27, FOO)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-3, FOO)); } @Test void testInsertWithNullText() { final TextStringBuilder sb = new TextStringBuilder(); sb.setNullText("null"); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, FOO)); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, FOO)); sb.insert(0, (Object) null); assertEquals("nullbarbaz", sb.toString()); sb.insert(0, FOO); assertEquals("foonullbarbaz", sb.toString()); sb.clear(); sb.append("barbaz"); assertEquals("barbaz", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(-1, "foo")); assertThrows(IndexOutOfBoundsException.class, () -> sb.insert(7, "foo")); sb.insert(0, (String) null); assertEquals("nullbarbaz", sb.toString()); sb.insert(0, "foo"); assertEquals("foonullbarbaz", sb.toString()); sb.insert(0, (char[]) null); assertEquals("nullfoonullbarbaz", sb.toString()); sb.insert(0, (char[]) null, 0, 0); assertEquals("nullnullfoonullbarbaz", sb.toString()); } /** See: https://issues.apache.org/jira/browse/LANG-299 */ @Test void testLang299() { final TextStringBuilder sb = new TextStringBuilder(1); sb.appendFixedWidthPadRight("foo", 1, '-'); assertEquals("f", sb.toString()); } } TextStringBuilderTest.java000066400000000000000000002573131511432740600336700ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Locale; import org.apache.commons.io.output.NullAppendable; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.matcher.StringMatcher; import org.apache.commons.text.matcher.StringMatcherFactory; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; /** * Tests {@link TextStringBuilder}. */ class TextStringBuilderTest { private static final class MockReadable implements Readable { private final CharBuffer src; MockReadable(final String src) { this.src = CharBuffer.wrap(src); } @Override public int read(final CharBuffer cb) throws IOException { return src.read(cb); } } static final StringMatcher A_NUMBER_MATCHER = (buffer, start, bufferStart, bufferEnd) -> { if (buffer[start] == 'A') { start++; if (start < bufferEnd && buffer[start] >= '0' && buffer[start] <= '9') { return 2; } } return 0; }; /** * Clear the string builder and fill up to the specified length. * * @param sb the string builder * @param length the length */ private static void fill(final TextStringBuilder sb, final int length) { sb.clear(); // Some initial data. final int limit = Math.min(64, length); for (int i = 0; i < limit; i++) { sb.append(' '); } // Fill by doubling while (sb.length() * 2L <= length) { sb.append(sb); } // Remaining fill sb.append(sb, 0, length - sb.length()); assertEquals(length, sb.length(), "Expected the buffer to be full to the given length"); } @Test void test_LANG_1131_EqualsWithNullTextStringBuilder() throws Exception { final TextStringBuilder sb = new TextStringBuilder(); final TextStringBuilder other = null; assertFalse(sb.equals(other)); } @Test void testAppendCharBuffer() { final TextStringBuilder sb1 = new TextStringBuilder(); final CharBuffer buf = CharBuffer.allocate(10); buf.append("0123456789"); buf.flip(); sb1.append(buf); assertEquals("0123456789", sb1.toString()); final TextStringBuilder sb2 = new TextStringBuilder(); sb2.append(buf, 1, 8); assertEquals("12345678", sb2.toString()); } @Test void testAppendCharBufferException() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final String text = "Test"; final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length()); buffer.put(text); buffer.flip(); try { sb.append(buffer, -1, 12); } catch (final StringIndexOutOfBoundsException e) { assertEquals("startIndex must be valid", e.getMessage()); } try { sb.append(buffer, 0, -1); } catch (final StringIndexOutOfBoundsException e) { assertEquals("length must be valid", e.getMessage()); } sb.append(buffer); assertEquals("1234567890Test", sb.toString()); } @Test void testAppendCharBufferNull() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final CharBuffer buffer = null; sb.append(buffer); assertEquals("1234567890", sb.toString()); final TextStringBuilder sb1 = new TextStringBuilder("1234567890"); final CharBuffer buffer1 = null; sb.append(buffer1, 0, 0); assertEquals("1234567890", sb1.toString()); } @Test void testAppendCharSequence() { final CharSequence obj0 = null; final CharSequence obj1 = new TextStringBuilder("test1"); final CharSequence obj2 = new StringBuilder("test2"); final CharSequence obj3 = new StringBuffer("test3"); final CharBuffer obj4 = CharBuffer.wrap("test4".toCharArray()); final TextStringBuilder sb0 = new TextStringBuilder(); assertEquals("", sb0.append(obj0).toString()); final TextStringBuilder sb1 = new TextStringBuilder(); assertEquals("test1", sb1.append(obj1).toString()); final TextStringBuilder sb2 = new TextStringBuilder(); assertEquals("test2", sb2.append(obj2).toString()); final TextStringBuilder sb3 = new TextStringBuilder(); assertEquals("test3", sb3.append(obj3).toString()); final TextStringBuilder sb4 = new TextStringBuilder(); assertEquals("test4", sb4.append(obj4).toString()); final TextStringBuilder sb5 = new TextStringBuilder(); assertEquals("", sb5.append(obj0, 0, 0).toString()); } @Test void testAppendln() { final TextStringBuilder sb1 = new TextStringBuilder(); final char ch = 'c'; assertEquals("c" + System.lineSeparator(), sb1.appendln(ch).toString()); } @Test void testAppendStringBuilderNull() { final TextStringBuilder sb1 = new TextStringBuilder(); final StringBuilder b = null; assertEquals("", sb1.append(b).toString()); final TextStringBuilder sb2 = new TextStringBuilder(); assertEquals("", sb2.append(b, 0, 0).toString()); } @Test void testAppendTakingTwoIntsWithIndexOutOfBoundsThrowsStringIndexOutOfBoundsExceptionTwo() { assertThrows(StringIndexOutOfBoundsException.class, () -> { final Charset charset = Charset.defaultCharset(); final ByteBuffer byteBuffer = charset.encode("asdf"); final CharBuffer charBuffer = charset.decode(byteBuffer); new TextStringBuilder().append(charBuffer, 933, 654); }); } @Test void testAppendTakingTwoIntsWithZeroThrowsStringIndexOutOfBoundsException() { assertThrows(StringIndexOutOfBoundsException.class, () -> { final Charset charset = Charset.defaultCharset(); final ByteBuffer byteBuffer = charset.encode("end < start"); final CharBuffer charBuffer = charset.decode(byteBuffer); new TextStringBuilder(630).append(charBuffer, 0, 630); }); } @Test void testAppendToAppendable() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final StringWriter writer = new StringWriter(); writer.append("Test"); sb.appendTo(NullAppendable.INSTANCE); assertEquals("Test", writer.toString()); } @Test void testAppendToCharBuffer() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final String text = "Test "; final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length()); buffer.put(text); sb.appendTo(buffer); buffer.flip(); assertEquals("Test 1234567890", buffer.toString()); } @Test void testAppendToStringBuffer() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final StringBuffer buffer = new StringBuffer("Test "); sb.appendTo(buffer); assertEquals("Test 1234567890", buffer.toString()); } @Test void testAppendToStringBuilder() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final StringBuilder builder = new StringBuilder("Test "); sb.appendTo(builder); assertEquals("Test 1234567890", builder.toString()); } @Test void testAppendToWriter() throws Exception { final TextStringBuilder sb = new TextStringBuilder("1234567890"); final StringWriter writer = new StringWriter(); writer.append("Test "); sb.appendTo(writer); assertEquals("Test 1234567890", writer.toString()); } @Test void testAsBuilder() { final TextStringBuilder sb = new TextStringBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor"); assertEquals(sb.toString(), sb.build()); } @Test void testAsReader() throws Exception { final TextStringBuilder sb = new TextStringBuilder("some text"); try (Reader reader = sb.asReader()) { assertTrue(reader.ready()); final char[] buf = new char[40]; assertEquals(9, reader.read(buf)); assertEquals("some text", new String(buf, 0, 9)); assertEquals(-1, reader.read()); assertFalse(reader.ready()); assertEquals(0, reader.skip(2)); assertEquals(0, reader.skip(-1)); assertTrue(reader.markSupported()); } try (Reader reader = sb.asReader()) { assertEquals('s', reader.read()); reader.mark(-1); final char[] array = new char[3]; assertEquals(3, reader.read(array, 0, 3)); assertEquals('o', array[0]); assertEquals('m', array[1]); assertEquals('e', array[2]); reader.reset(); assertEquals(1, reader.read(array, 1, 1)); assertEquals('o', array[0]); assertEquals('o', array[1]); assertEquals('e', array[2]); assertEquals(2, reader.skip(2)); assertEquals(' ', reader.read()); assertTrue(reader.ready()); reader.close(); assertTrue(reader.ready()); } try (Reader reader = sb.asReader()) { final char[] array = new char[3]; assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, -1, 0)); assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, 0, -1)); assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, 100, 1)); assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, 0, 100)); assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE)); assertEquals(0, reader.read(array, 0, 0)); assertEquals(0, array[0]); assertEquals(0, array[1]); assertEquals(0, array[2]); reader.skip(9); assertEquals(-1, reader.read(array, 0, 1)); reader.reset(); final char[] array2 = new char[30]; assertEquals(9, reader.read(array2, 0, 30)); } } @Test void testAsSupplier() { final TextStringBuilder sb = new TextStringBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor"); assertEquals(sb.toString(), sb.get()); } @Test void testAsTokenizer() throws Exception { // from Javadoc final TextStringBuilder b = new TextStringBuilder(); b.append("a b "); final StringTokenizer t = b.asTokenizer(); final String[] tokens1 = t.getTokenArray(); assertEquals(2, tokens1.length); assertEquals("a", tokens1[0]); assertEquals("b", tokens1[1]); assertEquals(2, t.size()); b.append("c d "); final String[] tokens2 = t.getTokenArray(); assertEquals(2, tokens2.length); assertEquals("a", tokens2[0]); assertEquals("b", tokens2[1]); assertEquals(2, t.size()); assertEquals("a", t.next()); assertEquals("b", t.next()); t.reset(); final String[] tokens3 = t.getTokenArray(); assertEquals(4, tokens3.length); assertEquals("a", tokens3[0]); assertEquals("b", tokens3[1]); assertEquals("c", tokens3[2]); assertEquals("d", tokens3[3]); assertEquals(4, t.size()); assertEquals("a", t.next()); assertEquals("b", t.next()); assertEquals("c", t.next()); assertEquals("d", t.next()); assertEquals("a b c d ", t.getContent()); } @Test void testAsWriter() throws Exception { final TextStringBuilder sb = new TextStringBuilder("base"); try (Writer writer = sb.asWriter()) { writer.write('l'); assertEquals("basel", sb.toString()); writer.write(new char[] { 'i', 'n' }); assertEquals("baselin", sb.toString()); writer.write(new char[] { 'n', 'e', 'r' }, 1, 2); assertEquals("baseliner", sb.toString()); writer.write(" rout"); assertEquals("baseliner rout", sb.toString()); writer.write("ping that server", 1, 3); assertEquals("baseliner routing", sb.toString()); writer.flush(); // no effect assertEquals("baseliner routing", sb.toString()); writer.close(); // no effect assertEquals("baseliner routing", sb.toString()); writer.write(" hi"); // works after close assertEquals("baseliner routing hi", sb.toString()); sb.setLength(4); // mix and match writer.write('d'); assertEquals("based", sb.toString()); } } @Test void testCapacity() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(sb.getBuffer().length, sb.capacity()); sb.append("HelloWorldHelloWorldHelloWorldHelloWorld"); assertEquals(sb.getBuffer().length, sb.capacity()); } @Test void testCapacityAndLength() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(32, sb.capacity()); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.ensureCapacity(32); assertTrue(sb.capacity() >= 32); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.append("foo"); assertTrue(sb.capacity() >= 32); assertEquals(3, sb.length()); assertEquals(3, sb.size()); assertFalse(sb.isEmpty()); sb.clear(); assertTrue(sb.capacity() >= 32); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); sb.append("123456789012345678901234567890123"); assertTrue(sb.capacity() > 32); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); sb.ensureCapacity(16); assertTrue(sb.capacity() > 16); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); sb.minimizeCapacity(); assertEquals(33, sb.capacity()); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1)); sb.setLength(33); assertEquals(33, sb.capacity()); assertEquals(33, sb.length()); assertEquals(33, sb.size()); assertFalse(sb.isEmpty()); sb.setLength(16); assertTrue(sb.capacity() >= 16); assertEquals(16, sb.length()); assertEquals(16, sb.size()); assertEquals("1234567890123456", sb.toString()); assertFalse(sb.isEmpty()); sb.setLength(32); assertTrue(sb.capacity() >= 32); assertEquals(32, sb.length()); assertEquals(32, sb.size()); assertEquals("1234567890123456\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sb.toString()); assertFalse(sb.isEmpty()); sb.setLength(0); assertTrue(sb.capacity() >= 32); assertEquals(0, sb.length()); assertEquals(0, sb.size()); assertTrue(sb.isEmpty()); } @Test void testChaining() { final TextStringBuilder sb = new TextStringBuilder(); assertSame(sb, sb.setNewLineText(null)); assertSame(sb, sb.setNullText(null)); assertSame(sb, sb.setLength(1)); assertSame(sb, sb.setCharAt(0, 'a')); assertSame(sb, sb.ensureCapacity(0)); assertSame(sb, sb.minimizeCapacity()); assertSame(sb, sb.clear()); assertSame(sb, sb.reverse()); assertSame(sb, sb.trim()); } @Test void testCharAt() { final TextStringBuilder sb = new TextStringBuilder(); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1)); sb.append("foo"); assertEquals('f', sb.charAt(0)); assertEquals('o', sb.charAt(1)); assertEquals('o', sb.charAt(2)); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1)); assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(3)); } @Test void testClear() { final TextStringBuilder sb = new TextStringBuilder(); sb.append("Hello"); sb.clear(); assertEquals(0, sb.length()); assertTrue(sb.getBuffer().length >= 5); } @Test void testConstructorCharSequence() { final CharBuffer str = CharBuffer.wrap("A"); final int length = str.length(); final TextStringBuilder sb = new TextStringBuilder(str); assertEquals(TextStringBuilder.CAPACITY + length, sb.capacity()); assertEquals(length, sb.toCharArray().length); } @Test void testConstructorDefault() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(TextStringBuilder.CAPACITY, sb.capacity()); assertEquals(0, sb.toCharArray().length); } @Test void testConstructors() { final TextStringBuilder sb0 = new TextStringBuilder(); assertEquals(32, sb0.capacity()); assertEquals(0, sb0.length()); assertEquals(0, sb0.size()); final TextStringBuilder sb1 = new TextStringBuilder(32); assertEquals(32, sb1.capacity()); assertEquals(0, sb1.length()); assertEquals(0, sb1.size()); final TextStringBuilder sb2 = new TextStringBuilder(0); assertEquals(32, sb2.capacity()); assertEquals(0, sb2.length()); assertEquals(0, sb2.size()); final TextStringBuilder sb3 = new TextStringBuilder(-1); assertEquals(32, sb3.capacity()); assertEquals(0, sb3.length()); assertEquals(0, sb3.size()); final TextStringBuilder sb4 = new TextStringBuilder(1); assertEquals(1, sb4.capacity()); assertEquals(0, sb4.length()); assertEquals(0, sb4.size()); final TextStringBuilder sb5 = new TextStringBuilder((String) null); assertEquals(32, sb5.capacity()); assertEquals(0, sb5.length()); assertEquals(0, sb5.size()); final TextStringBuilder sb6 = new TextStringBuilder(""); assertEquals(32, sb6.capacity()); assertEquals(0, sb6.length()); assertEquals(0, sb6.size()); final TextStringBuilder sb7 = new TextStringBuilder("foo"); assertEquals(35, sb7.capacity()); assertEquals(3, sb7.length()); assertEquals(3, sb7.size()); } @Test void testConstructorString() { final String str = "A"; final int length = str.length(); final TextStringBuilder sb = new TextStringBuilder(str); assertEquals(TextStringBuilder.CAPACITY + length, sb.capacity()); assertEquals(length, sb.toCharArray().length); } @Test void testContains_char() { final TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz"); assertTrue(sb.contains('a')); assertTrue(sb.contains('o')); assertTrue(sb.contains('z')); assertFalse(sb.contains('1')); } @Test void testContains_String() { final TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz"); assertTrue(sb.contains("a")); assertTrue(sb.contains("pq")); assertTrue(sb.contains("z")); assertFalse(sb.contains("zyx")); assertFalse(sb.contains((String) null)); } @Test void testContains_StringMatcher() { TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz"); assertTrue(sb.contains(StringMatcherFactory.INSTANCE.charMatcher('a'))); assertTrue(sb.contains(StringMatcherFactory.INSTANCE.stringMatcher("pq"))); assertTrue(sb.contains(StringMatcherFactory.INSTANCE.charMatcher('z'))); assertFalse(sb.contains(StringMatcherFactory.INSTANCE.stringMatcher("zy"))); assertFalse(sb.contains((StringMatcher) null)); sb = new TextStringBuilder(); assertFalse(sb.contains(A_NUMBER_MATCHER)); sb.append("B A1 C"); assertTrue(sb.contains(A_NUMBER_MATCHER)); } @Test void testDeleteAll_char() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.deleteAll('X'); assertEquals("abcbccba", sb.toString()); sb.deleteAll('a'); assertEquals("bcbccb", sb.toString()); sb.deleteAll('c'); assertEquals("bbb", sb.toString()); sb.deleteAll('b'); assertEquals("", sb.toString()); sb = new TextStringBuilder(""); sb.deleteAll('b'); assertEquals("", sb.toString()); } @Test void testDeleteAll_String() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.deleteAll((String) null); assertEquals("abcbccba", sb.toString()); sb.deleteAll(""); assertEquals("abcbccba", sb.toString()); sb.deleteAll("X"); assertEquals("abcbccba", sb.toString()); sb.deleteAll("a"); assertEquals("bcbccb", sb.toString()); sb.deleteAll("c"); assertEquals("bbb", sb.toString()); sb.deleteAll("b"); assertEquals("", sb.toString()); sb = new TextStringBuilder("abcbccba"); sb.deleteAll("bc"); assertEquals("acba", sb.toString()); sb = new TextStringBuilder(""); sb.deleteAll("bc"); assertEquals("", sb.toString()); } @Test void testDeleteAll_StringMatcher() { TextStringBuilder sb = new TextStringBuilder("A0xA1A2yA3"); sb.deleteAll((StringMatcher) null); assertEquals("A0xA1A2yA3", sb.toString()); sb.deleteAll(A_NUMBER_MATCHER); assertEquals("xy", sb.toString()); sb = new TextStringBuilder("Ax1"); sb.deleteAll(A_NUMBER_MATCHER); assertEquals("Ax1", sb.toString()); sb = new TextStringBuilder(""); sb.deleteAll(A_NUMBER_MATCHER); assertEquals("", sb.toString()); } @Test void testDeleteCharAt() { final String str = "abc"; // final TextStringBuilder sb1 = new TextStringBuilder(str); sb1.deleteCharAt(0); assertEquals("bc", sb1.toString()); // final TextStringBuilder sb2 = new TextStringBuilder(str); sb2.deleteCharAt(str.length() - 1); assertEquals("ab", sb2.toString()); // final TextStringBuilder sb3 = new TextStringBuilder(str); assertThrows(IndexOutOfBoundsException.class, () -> sb3.deleteCharAt(str.length())); assertThrows(IndexOutOfBoundsException.class, () -> sb3.deleteCharAt(1000)); } @Test void testDeleteCharAtWithNegative() { assertThrows(StringIndexOutOfBoundsException.class, () -> new TextStringBuilder().deleteCharAt(-1258)); } @Test void testDeleteFirst_char() { TextStringBuilder sb = new TextStringBuilder("abcba"); sb.deleteFirst('X'); assertEquals("abcba", sb.toString()); sb.deleteFirst('a'); assertEquals("bcba", sb.toString()); sb.deleteFirst('c'); assertEquals("bba", sb.toString()); sb.deleteFirst('b'); assertEquals("ba", sb.toString()); sb = new TextStringBuilder(""); sb.deleteFirst('b'); assertEquals("", sb.toString()); } @Test void testDeleteFirst_String() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.deleteFirst((String) null); assertEquals("abcbccba", sb.toString()); sb.deleteFirst(""); assertEquals("abcbccba", sb.toString()); sb.deleteFirst("X"); assertEquals("abcbccba", sb.toString()); sb.deleteFirst("a"); assertEquals("bcbccba", sb.toString()); sb.deleteFirst("c"); assertEquals("bbccba", sb.toString()); sb.deleteFirst("b"); assertEquals("bccba", sb.toString()); sb = new TextStringBuilder("abcbccba"); sb.deleteFirst("bc"); assertEquals("abccba", sb.toString()); sb = new TextStringBuilder(""); sb.deleteFirst("bc"); assertEquals("", sb.toString()); } @Test void testDeleteFirst_StringMatcher() { TextStringBuilder sb = new TextStringBuilder("A0xA1A2yA3"); sb.deleteFirst((StringMatcher) null); assertEquals("A0xA1A2yA3", sb.toString()); sb.deleteFirst(A_NUMBER_MATCHER); assertEquals("xA1A2yA3", sb.toString()); sb = new TextStringBuilder("Ax1"); sb.deleteFirst(A_NUMBER_MATCHER); assertEquals("Ax1", sb.toString()); sb = new TextStringBuilder(""); sb.deleteFirst(A_NUMBER_MATCHER); assertEquals("", sb.toString()); } @Test void testDeleteIntInt() { final TextStringBuilder sb = new TextStringBuilder("abc"); sb.delete(0, 1); assertEquals("bc", sb.toString()); sb.delete(1, 2); assertEquals("b", sb.toString()); sb.delete(0, 1); assertEquals("", sb.toString()); sb.delete(0, 1000); assertEquals("", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(1, 2)); assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(-1, 1)); assertThrows(IndexOutOfBoundsException.class, () -> new TextStringBuilder("anything").delete(2, 1)); } @Test void testDrainChar() { final String str = "abc"; // final TextStringBuilder sb1 = new TextStringBuilder(str); assertEquals('a', sb1.drainChar(0)); assertEquals("bc", sb1.toString()); // final TextStringBuilder sb2 = new TextStringBuilder(str); assertEquals('c', sb2.drainChar(str.length() - 1)); assertEquals("ab", sb2.toString()); // final TextStringBuilder sb3 = new TextStringBuilder(str); assertThrows(IndexOutOfBoundsException.class, () -> sb3.drainChar(str.length())); assertThrows(IndexOutOfBoundsException.class, () -> sb3.drainChar(1000)); } @Test void testDrainCharsIntIntCharArrayInt() { final String data = "junit"; final char[] array = new char[data.length()]; final TextStringBuilder sb = new TextStringBuilder(); // empty buffer assertEquals(0, sb.drainChars(0, 5, array, 1)); assertEquals(0, sb.drainChars(0, 5, ArrayUtils.EMPTY_CHAR_ARRAY, 1)); // empty buffer, 0 length request assertEquals(0, sb.drainChars(5, 5, array, 1)); sb.append(data); assertEquals(0, sb.drainChars(5, 5, array, 1)); assertEquals(5, sb.drainChars(0, 5, array, 0)); assertArrayEquals(data.toCharArray(), array); final char[] b = new char[5]; sb.set(data); assertEquals(2, sb.drainChars(0, 2, b, 3)); assertArrayEquals(new char[] { 0, 0, 0, 'j', 'u' }, b); assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(-1, 0, b, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(0, -1, array, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(4, 2, array, 0)); // get and delete it all. sb.set(data); assertEquals(data.length(), sb.drainChars(0, sb.length() + 1, array, 0)); assertArrayEquals(data.toCharArray(), array); // get and delete more than there is sb.set(data); assertEquals(data.length(), sb.drainChars(0, sb.length() + 10, array, 0)); assertArrayEquals(data.toCharArray(), array); // get and delete more than can fit sb.set(data); int targetIndex = 1; Arrays.fill(array, '-'); assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 10, array, targetIndex)); assertArrayEquals("-juni".toCharArray(), array); // get and delete more than can fit sb.set(data); Arrays.fill(array, '-'); assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 1, array, targetIndex)); assertArrayEquals("-juni".toCharArray(), array); // get and delete more than can fit sb.set(data); targetIndex = 2; Arrays.fill(array, '-'); assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 1, array, targetIndex)); assertArrayEquals("--jun".toCharArray(), array); } @Test void testEndsWith() { final TextStringBuilder sb = new TextStringBuilder(); assertFalse(sb.endsWith("a")); assertFalse(sb.endsWith("c")); assertTrue(sb.endsWith("")); assertFalse(sb.endsWith(null)); sb.append("abc"); assertTrue(sb.endsWith("c")); assertTrue(sb.endsWith("bc")); assertTrue(sb.endsWith("abc")); assertFalse(sb.endsWith("cba")); assertFalse(sb.endsWith("abcd")); assertFalse(sb.endsWith(" abc")); assertFalse(sb.endsWith("abc ")); } @Test void testEnsureCapacity() { final TextStringBuilder sb = new TextStringBuilder(); sb.ensureCapacity(2); assertTrue(sb.capacity() >= 2); sb.ensureCapacity(-1); assertTrue(sb.capacity() >= 0); sb.append("HelloWorld"); sb.ensureCapacity(40); assertTrue(sb.capacity() >= 40); } @Test void testEnsureCapacityOutOfMemoryError() { final TextStringBuilder sb = new TextStringBuilder(); // Should not be a NegativeArraySizeException sb.ensureCapacity(Integer.MIN_VALUE); sb.ensureCapacity(-1); sb.ensureCapacity(0); // Might fail in a CI: // sb.ensureCapacity(Integer.MAX_VALUE / 2); sb.ensureCapacity(10_000); assertThrows(OutOfMemoryError.class, () -> sb.ensureCapacity(Integer.MAX_VALUE)); } @Test void testEquals() { final TextStringBuilder sb1 = new TextStringBuilder(50); final TextStringBuilder sb2 = new TextStringBuilder(100); assertTrue(sb1.equals(sb2)); assertTrue(sb1.equals(sb1)); assertTrue(sb2.equals(sb2)); assertEquals(sb1, sb2); sb1.append("abc"); assertFalse(sb1.equals(sb2)); assertNotEquals(sb1, sb2); sb2.append("ABC"); assertFalse(sb1.equals(sb2)); assertNotEquals(sb1, sb2); sb2.set("abc"); assertTrue(sb1.equals(sb2)); assertEquals(sb1, sb2); assertNotEquals(sb1, Integer.valueOf(1)); assertNotEquals("abc", sb1); } @Test void testEqualsIgnoreCase() { final TextStringBuilder sb1 = new TextStringBuilder(); final TextStringBuilder sb2 = new TextStringBuilder(); assertTrue(sb1.equalsIgnoreCase(sb1)); assertTrue(sb1.equalsIgnoreCase(sb2)); assertTrue(sb2.equalsIgnoreCase(sb2)); sb1.append("abc"); assertFalse(sb1.equalsIgnoreCase(sb2)); sb2.append("ABC"); assertTrue(sb1.equalsIgnoreCase(sb2)); sb2.set("abc"); assertTrue(sb1.equalsIgnoreCase(sb2)); assertTrue(sb1.equalsIgnoreCase(sb1)); assertTrue(sb2.equalsIgnoreCase(sb2)); sb2.set("aBc"); assertTrue(sb1.equalsIgnoreCase(sb2)); final Locale turkish = Locale.forLanguageTag("tr"); assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new TextStringBuilder("title".toLowerCase(turkish)))); assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new TextStringBuilder("TITLE".toLowerCase(turkish)))); assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("TITLE".toLowerCase(turkish)))); assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("title".toLowerCase(turkish)))); // // assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new // TextStringBuilder("title".toUpperCase(turkish)))); // assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new // TextStringBuilder("TITLE".toUpperCase(turkish)))); assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("TITLE".toUpperCase(turkish)))); // assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new // TextStringBuilder("title".toUpperCase(turkish)))); } @Test void testGetChars() { final TextStringBuilder sb = new TextStringBuilder(); char[] input = new char[10]; char[] a = sb.getChars(input); assertSame(input, a); assertArrayEquals(new char[10], a); sb.append("junit"); a = sb.getChars(input); assertSame(input, a); assertArrayEquals(new char[] { 'j', 'u', 'n', 'i', 't', 0, 0, 0, 0, 0 }, a); a = sb.getChars(null); assertNotSame(input, a); assertEquals(5, a.length); assertArrayEquals("junit".toCharArray(), a); input = new char[5]; a = sb.getChars(input); assertSame(input, a); input = new char[4]; a = sb.getChars(input); assertNotSame(input, a); } @Test void testGetCharsIntIntCharArrayInt() { final TextStringBuilder sb = new TextStringBuilder(); final char[] array1 = new char[1]; sb.getChars(0, 0, array1, 0); assertArrayEquals(new char[1], array1); sb.set("junit"); sb.getChars(0, 1, array1, 0); assertArrayEquals(new char[] { 'j' }, array1); final char[] array = new char[5]; sb.getChars(0, 5, array, 0); assertArrayEquals(new char[] { 'j', 'u', 'n', 'i', 't' }, array); final char[] b = new char[5]; sb.getChars(0, 2, b, 3); assertArrayEquals(new char[] { 0, 0, 0, 'j', 'u' }, b); assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(-1, 0, b, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(0, -1, array, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(0, 20, array, 0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(4, 2, array, 0)); } @Test void testGetSetNewLineText() { final TextStringBuilder sb = new TextStringBuilder(); assertNull(sb.getNewLineText()); sb.setNewLineText("#"); assertEquals("#", sb.getNewLineText()); sb.setNewLineText(""); assertEquals("", sb.getNewLineText()); sb.setNewLineText((String) null); assertNull(sb.getNewLineText()); } @Test void testGetSetNullText() { final TextStringBuilder sb = new TextStringBuilder(); assertNull(sb.getNullText()); sb.setNullText("null"); assertEquals("null", sb.getNullText()); sb.setNullText(""); assertNull(sb.getNullText()); sb.setNullText("NULL"); assertEquals("NULL", sb.getNullText()); sb.setNullText((String) null); assertNull(sb.getNullText()); } @Test void testHashCode() { final TextStringBuilder sb = new TextStringBuilder(); final int hc1a = sb.hashCode(); final int hc1b = sb.hashCode(); assertEquals(hc1a, hc1b); // following TEXT-211 : the hash code of the buffer may not be equals to the hash code of the TextStringBuilder itself final int emptyHc = Arrays.hashCode(sb.getBuffer()); assertNotEquals(emptyHc, hc1a); sb.append("abc"); final int hc2a = sb.hashCode(); final int hc2b = sb.hashCode(); assertEquals(hc2a, hc2b); final TextStringBuilder sb2 = new TextStringBuilder(100); final TextStringBuilder sb3 = new TextStringBuilder(10); final int hc2 = sb2.hashCode(); final int hc3 = sb3.hashCode(); assertEquals(hc2, hc3); sb2.append("abc"); sb3.append("abc"); final int hc2b2 = sb2.hashCode(); final int hc3b2 = sb3.hashCode(); assertEquals(hc2b2, hc3b2); } @Test void testIndexOf_char() { final TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(0, sb.indexOf('a')); // should work like String#indexOf assertEquals("abab".indexOf('a'), sb.indexOf('a')); assertEquals(1, sb.indexOf('b')); assertEquals("abab".indexOf('b'), sb.indexOf('b')); assertEquals(-1, sb.indexOf('z')); } @Test void testIndexOf_char_int() { TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(0, sb.indexOf('a', -1)); assertEquals(0, sb.indexOf('a', 0)); assertEquals(2, sb.indexOf('a', 1)); assertEquals(-1, sb.indexOf('a', 4)); assertEquals(-1, sb.indexOf('a', 5)); // should work like String#indexOf assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1)); assertEquals(3, sb.indexOf('b', 2)); assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2)); assertEquals(-1, sb.indexOf('z', 2)); sb = new TextStringBuilder("xyzabc"); assertEquals(2, sb.indexOf('z', 0)); assertEquals(-1, sb.indexOf('z', 3)); } @Test void testIndexOf_String() { final TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(0, sb.indexOf("a")); // should work like String#indexOf assertEquals("abab".indexOf("a"), sb.indexOf("a")); assertEquals(0, sb.indexOf("ab")); // should work like String#indexOf assertEquals("abab".indexOf("ab"), sb.indexOf("ab")); assertEquals(1, sb.indexOf("b")); assertEquals("abab".indexOf("b"), sb.indexOf("b")); assertEquals(1, sb.indexOf("ba")); assertEquals("abab".indexOf("ba"), sb.indexOf("ba")); assertEquals(-1, sb.indexOf("z")); assertEquals(-1, sb.indexOf((String) null)); } @Test void testIndexOf_String_int() { TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(0, sb.indexOf("a", -1)); assertEquals(0, sb.indexOf("a", 0)); assertEquals(2, sb.indexOf("a", 1)); assertEquals(2, sb.indexOf("a", 2)); assertEquals(-1, sb.indexOf("a", 3)); assertEquals(-1, sb.indexOf("a", 4)); assertEquals(-1, sb.indexOf("a", 5)); assertEquals(-1, sb.indexOf("abcdef", 0)); assertEquals(0, sb.indexOf("", 0)); assertEquals(1, sb.indexOf("", 1)); // should work like String#indexOf assertEquals("abab".indexOf("a", 1), sb.indexOf("a", 1)); assertEquals(2, sb.indexOf("ab", 1)); // should work like String#indexOf assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1)); assertEquals(3, sb.indexOf("b", 2)); assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2)); assertEquals(1, sb.indexOf("ba", 1)); assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2)); assertEquals(-1, sb.indexOf("z", 2)); sb = new TextStringBuilder("xyzabc"); assertEquals(2, sb.indexOf("za", 0)); assertEquals(-1, sb.indexOf("za", 3)); assertEquals(-1, sb.indexOf((String) null, 2)); } @Test void testIndexOf_StringMatcher() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(-1, sb.indexOf((StringMatcher) null)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'))); sb.append("ab bd"); assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'))); assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'))); assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher())); assertEquals(4, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('d'))); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.noneMatcher())); assertEquals(-1, sb.indexOf((StringMatcher) null)); sb.append(" A1 junction"); assertEquals(6, sb.indexOf(A_NUMBER_MATCHER)); } @Test void testIndexOf_StringMatcher_int() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(-1, sb.indexOf((StringMatcher) null, 2)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0)); sb.append("ab bd"); assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -2)); assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 20)); assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), -1)); assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 0)); assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 1)); assertEquals(3, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 2)); assertEquals(3, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 3)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 4)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 5)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 6)); assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), -2)); assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 0)); assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 2)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 4)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 20)); assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.noneMatcher(), 0)); assertEquals(-1, sb.indexOf((StringMatcher) null, 0)); sb.append(" A1 junction with A2"); assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5)); assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6)); assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7)); assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22)); assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23)); assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24)); } @Test void testIndexOfLang294() { final TextStringBuilder sb = new TextStringBuilder("onetwothree"); sb.deleteFirst("three"); assertEquals(-1, sb.indexOf("three")); } @Test void testIsEmpty() { final TextStringBuilder sb = new TextStringBuilder(); assertTrue(sb.isEmpty()); sb.append("Hello"); assertFalse(sb.isEmpty()); sb.clear(); assertTrue(sb.isEmpty()); } @Test void testIsNotEmpty() { final TextStringBuilder sb = new TextStringBuilder(); assertFalse(sb.isNotEmpty()); sb.append("Hello"); assertTrue(sb.isNotEmpty()); sb.clear(); assertFalse(sb.isNotEmpty()); } @Test void testLang294() { final TextStringBuilder sb = new TextStringBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n"); sb.deleteAll("\n%BLAH%"); assertEquals("\nDo more stuff\neven more stuff\n", sb.toString()); } @Test void testLang295() { final TextStringBuilder sb = new TextStringBuilder("onetwothree"); sb.deleteFirst("three"); assertFalse(sb.contains('h'), "The contains(char) method is looking beyond the end of the string"); assertEquals(-1, sb.indexOf('h'), "The indexOf(char) method is looking beyond the end of the string"); } @Test void testLang412Left() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendFixedWidthPadLeft(null, 10, '*'); assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadLeft correctly"); } @Test void testLang412Right() { final TextStringBuilder sb = new TextStringBuilder(); sb.appendFixedWidthPadRight(null, 10, '*'); assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadRight correctly"); } @Test void testLastIndexOf_char() { final TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(2, sb.lastIndexOf('a')); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf('a'), sb.lastIndexOf('a')); assertEquals(3, sb.lastIndexOf('b')); assertEquals("abab".lastIndexOf('b'), sb.lastIndexOf('b')); assertEquals(-1, sb.lastIndexOf('z')); } @Test void testLastIndexOf_char_int() { TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(-1, sb.lastIndexOf('a', -1)); assertEquals(0, sb.lastIndexOf('a', 0)); assertEquals(0, sb.lastIndexOf('a', 1)); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1)); assertEquals(1, sb.lastIndexOf('b', 2)); assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2)); assertEquals(-1, sb.lastIndexOf('z', 2)); sb = new TextStringBuilder("xyzabc"); assertEquals(2, sb.lastIndexOf('z', sb.length())); assertEquals(-1, sb.lastIndexOf('z', 1)); } @Test void testLastIndexOf_String() { final TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(2, sb.lastIndexOf("a")); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a")); assertEquals(2, sb.lastIndexOf("ab")); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab")); assertEquals(3, sb.lastIndexOf("b")); assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b")); assertEquals(1, sb.lastIndexOf("ba")); assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba")); assertEquals(-1, sb.lastIndexOf("z")); assertEquals(-1, sb.lastIndexOf((String) null)); } @Test void testLastIndexOf_String_int() { TextStringBuilder sb = new TextStringBuilder("abab"); assertEquals(-1, sb.lastIndexOf("a", -1)); assertEquals(0, sb.lastIndexOf("a", 0)); assertEquals(0, sb.lastIndexOf("a", 1)); assertEquals(2, sb.lastIndexOf("a", 2)); assertEquals(2, sb.lastIndexOf("a", 3)); assertEquals(2, sb.lastIndexOf("a", 4)); assertEquals(2, sb.lastIndexOf("a", 5)); assertEquals(-1, sb.lastIndexOf("abcdef", 3)); assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3)); assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1)); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1)); assertEquals(0, sb.lastIndexOf("ab", 1)); // should work like String#lastIndexOf assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1)); assertEquals(1, sb.lastIndexOf("b", 2)); assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2)); assertEquals(1, sb.lastIndexOf("ba", 2)); assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2)); assertEquals(-1, sb.lastIndexOf("z", 2)); sb = new TextStringBuilder("xyzabc"); assertEquals(2, sb.lastIndexOf("za", sb.length())); assertEquals(-1, sb.lastIndexOf("za", 1)); assertEquals(-1, sb.lastIndexOf((String) null, 2)); } @Test void testLastIndexOf_StringMatcher() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(-1, sb.lastIndexOf((StringMatcher) null)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'))); sb.append("ab bd"); assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'))); assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'))); assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher())); assertEquals(4, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('d'))); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.noneMatcher())); assertEquals(-1, sb.lastIndexOf((StringMatcher) null)); sb.append(" A1 junction"); assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER)); } @Test void testLastIndexOf_StringMatcher_int() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(-1, sb.lastIndexOf((StringMatcher) null, 2)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -1)); sb.append("ab bd"); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -2)); assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0)); assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2)); assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 20)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), -1)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 0)); assertEquals(1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 1)); assertEquals(1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 2)); assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 3)); assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 4)); assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 5)); assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 6)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), -2)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 0)); assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 2)); assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 4)); assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 20)); assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.noneMatcher(), 0)); assertEquals(-1, sb.lastIndexOf((StringMatcher) null, 0)); sb.append(" A1 junction with A2"); assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5)); assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1 // is outside // bounds assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7)); assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22)); assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2 // is outside // bounds assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24)); } @Test void testLeftString() { final TextStringBuilder sb = new TextStringBuilder("left right"); assertEquals("left", sb.leftString(4)); assertEquals("", sb.leftString(0)); assertEquals("", sb.leftString(-5)); assertEquals("left right", sb.leftString(15)); } @Test void testLength() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(0, sb.length()); sb.append("Hello"); assertEquals(5, sb.length()); } @Test void testMidString() { final TextStringBuilder sb = new TextStringBuilder("hello goodbye hello"); assertEquals("goodbye", sb.midString(6, 7)); assertEquals("hello", sb.midString(0, 5)); assertEquals("hello", sb.midString(-5, 5)); assertEquals("", sb.midString(0, -1)); assertEquals("", sb.midString(20, 2)); assertEquals("hello", sb.midString(14, 22)); } @Test void testMinimizeCapacity() { final TextStringBuilder sb = new TextStringBuilder(); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); sb.append("HelloWorld"); sb.minimizeCapacity(); assertEquals(10, sb.capacity()); } @Test void testOutOfMemoryError() { // This test is memory hungry requiring at least 7GiB of memory. // By default expansion will double the buffer size. If we repeat // add 1GiB of char data then we require at maximum: // 1GiB char[] data // 2GiB char[] buffer // ~4GiB char[] new buffer during reallocation // Attempts to guess the amount of free memory available using // the java.lang.Runtime/java.lang.management objects to // skip the test often did not work. // So here we just run the test and return a skip result if the // OutOfMemoryError occurs too early. final TextStringBuilder sb = new TextStringBuilder(); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); // 1GiB char[] buffer: length is roughly 1/4 the maximum array size final char[] chars = new char[1 << 29]; // With infinite memory it should be possible to add this 3 times. try { for (int i = 0; i < 3; i++) { sb.append(chars); } } catch (final OutOfMemoryError ignored) { Assumptions.abort("Not enough memory for the test"); } // Now at 3/4 of the maximum array length. // Adding is not possible so we expect an OOM error. assertThrows(OutOfMemoryError.class, () -> sb.append(chars)); } @Test void testOutOfMemoryError2() { // This test is memory hungry requiring at least 4GiB of memory // in a single allocation. If not possible then skip the test. final TextStringBuilder sb = new TextStringBuilder(); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); // Allocate a lot final int small = 10; final int big = Integer.MAX_VALUE - small; final char[] extra = new char[small + 1]; try { sb.ensureCapacity(big); } catch (final OutOfMemoryError ignored) { Assumptions.abort("Not enough memory for the test"); } fill(sb, big); // Adding more than the maximum array size is not possible so we expect an OOM error. assertThrows(OutOfMemoryError.class, () -> sb.append(extra)); } @Test void testOutOfMemoryError3() { // This test is memory hungry requiring at least 2GiB of memory // in a single allocation. If not possible then skip the test. final TextStringBuilder sb = new TextStringBuilder(); sb.minimizeCapacity(); assertEquals(0, sb.capacity()); final int length = 1 << 30; try { sb.ensureCapacity(length); } catch (final OutOfMemoryError ignored) { Assumptions.abort("Not enough memory for the test"); } fill(sb, length); // Adding to itself requires a new buffer above the limits of an array assertThrows(OutOfMemoryError.class, () -> sb.append(sb)); } @Test void testReadFromCharBuffer() throws Exception { String s = ""; for (int i = 0; i < 100; ++i) { final TextStringBuilder sb = new TextStringBuilder(); final int len = sb.readFrom(CharBuffer.wrap(s)); assertEquals(s.length(), len); assertEquals(s, sb.toString()); s += Integer.toString(i); } } @Test void testReadFromCharBufferAppendsToEnd() throws Exception { final TextStringBuilder sb = new TextStringBuilder("Test"); sb.readFrom(CharBuffer.wrap(" 123")); assertEquals("Test 123", sb.toString()); } @Test void testReadFromReadable() throws Exception { String s = ""; for (int i = 0; i < 100; ++i) { final TextStringBuilder sb = new TextStringBuilder(); final int len = sb.readFrom(new MockReadable(s)); assertEquals(s.length(), len); assertEquals(s, sb.toString()); s += Integer.toString(i); } } @Test void testReadFromReadableAppendsToEnd() throws Exception { final TextStringBuilder sb = new TextStringBuilder("Test"); sb.readFrom(new MockReadable(" 123")); assertEquals("Test 123", sb.toString()); } @Test void testReadFromReader() throws Exception { String s = "1"; for (int i = 0; i < 100; ++i) { final TextStringBuilder sb = new TextStringBuilder(); final int len = sb.readFrom(new StringReader(s)); assertEquals(s.length(), len); assertEquals(s, sb.toString()); s += Integer.toString(i); } } @Test void testReadFromReaderAppendsToEnd() throws Exception { final TextStringBuilder sb = new TextStringBuilder("Test"); sb.readFrom(new StringReader(" 123")); assertEquals("Test 123", sb.toString()); } @Test void testReadFromReaderEmpty() throws Exception { final TextStringBuilder sb = new TextStringBuilder(); final int len = sb.readFrom(new StringReader(StringUtils.EMPTY)); assertEquals(-1, len); assertEquals(StringUtils.EMPTY, sb.toString()); } @Test void testReadFromReaderInt() throws Exception { String str = ""; for (int i = 0; i < 100; ++i) { final TextStringBuilder sb = new TextStringBuilder(); final int len = sb.readFrom(new StringReader(str), str.length()); assertEquals(str.length(), len); assertEquals(str, sb.toString()); str += Integer.toString(i); } // TextStringBuilder sb; int count; int target; final String source = "abc"; final int sourceLen = source.length(); // empty target = -1; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(StringUtils.EMPTY), target); assertEquals(0, count); assertEquals(0, sb.size()); assertEquals(source.substring(0, 0), sb.toString()); // target = -1; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(source), target); assertEquals(0, count); assertEquals(0, sb.size()); assertEquals(source.substring(0, 0), sb.toString()); // target = 0; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(source), target); assertEquals(target, count); assertEquals(target, sb.size()); assertEquals(source.substring(0, target), sb.toString()); // target = 1; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(source), target); assertEquals(target, count); assertEquals(target, sb.size()); assertEquals(source.substring(0, target), sb.toString()); // target = 2; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(source), target); assertEquals(target, count); assertEquals(target, sb.size()); assertEquals(source.substring(0, target), sb.toString()); // target = 3; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(source), target); assertEquals(target, count); assertEquals(target, sb.size()); assertEquals(source.substring(0, target), sb.toString()); // target = 4; sb = new TextStringBuilder(); count = sb.readFrom(new StringReader(source), target); assertEquals(sourceLen, count); assertEquals(sourceLen, sb.size()); assertEquals(source.substring(0, sourceLen), sb.toString()); } @Test void testReadFromReaderIntEmpty() throws Exception { final TextStringBuilder sb = new TextStringBuilder(); final int len = sb.readFrom(new StringReader(StringUtils.EMPTY), 1); assertEquals(-1, len); assertEquals(StringUtils.EMPTY, sb.toString()); } @Test void testReplace_int_int_String() { final TextStringBuilder sb = new TextStringBuilder("abc"); sb.replace(0, 1, "d"); assertEquals("dbc", sb.toString()); sb.replace(0, 1, "aaa"); assertEquals("aaabc", sb.toString()); sb.replace(0, 3, ""); assertEquals("bc", sb.toString()); sb.replace(1, 2, (String) null); assertEquals("b", sb.toString()); sb.replace(1, 1000, "text"); assertEquals("btext", sb.toString()); sb.replace(0, 1000, "text"); assertEquals("text", sb.toString()); final TextStringBuilder builder = new TextStringBuilder("atext"); builder.replace(1, 1, "ny"); assertEquals("anytext", builder.toString()); assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(2, 1, "anything")); builder.clear(); assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(1, 2, "anything")); assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(-1, 1, "anything")); } @Test void testReplace_StringMatcher_String_int_int_int_VaryCount() { TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, -1); assertEquals("-x--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 0); assertEquals("aaxaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 1); assertEquals("-xaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 2); assertEquals("-x-aayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 3); assertEquals("-x--yaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 4); assertEquals("-x--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 5); assertEquals("-x--y-", sb.toString()); } @Test void testReplace_StringMatcher_String_int_int_int_VaryEndIndex() { TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 0, -1); assertEquals("aaxaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 2, -1); assertEquals("-xaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 3, -1); assertEquals("-xaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 4, -1); assertEquals("-xaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 5, -1); assertEquals("-x-aayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 6, -1); assertEquals("-x-aayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 7, -1); assertEquals("-x--yaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 8, -1); assertEquals("-x--yaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 9, -1); assertEquals("-x--yaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, -1); assertEquals("-x--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 1000, -1); assertEquals("-x--y-", sb.toString()); final TextStringBuilder builder = new TextStringBuilder("aaxaaaayaa"); assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 2, 1, -1)); assertEquals("aaxaaaayaa", builder.toString()); } @Test void testReplace_StringMatcher_String_int_int_int_VaryMatcher() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replace((StringMatcher) null, "x", 0, sb.length(), -1); assertEquals("abcbccba", sb.toString()); sb.replace(StringMatcherFactory.INSTANCE.charMatcher('a'), "x", 0, sb.length(), -1); assertEquals("xbcbccbx", sb.toString()); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "x", 0, sb.length(), -1); assertEquals("xbxcxx", sb.toString()); sb = new TextStringBuilder("A1-A2A3-A4"); sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1); assertEquals("***-******-***", sb.toString()); sb = new TextStringBuilder(); sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1); assertEquals("", sb.toString()); } @Test void testReplace_StringMatcher_String_int_int_int_VaryReplace() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "cb", 0, sb.length(), -1); assertEquals("abcbccba", sb.toString()); sb = new TextStringBuilder("abcbccba"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-", 0, sb.length(), -1); assertEquals("ab-c-a", sb.toString()); sb = new TextStringBuilder("abcbccba"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "+++", 0, sb.length(), -1); assertEquals("ab+++c+++a", sb.toString()); sb = new TextStringBuilder("abcbccba"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "", 0, sb.length(), -1); assertEquals("abca", sb.toString()); sb = new TextStringBuilder("abcbccba"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), null, 0, sb.length(), -1); assertEquals("abca", sb.toString()); } @Test void testReplace_StringMatcher_String_int_int_int_VaryStartIndex() { TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, sb.length(), -1); assertEquals("-x--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 1, sb.length(), -1); assertEquals("aax--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 2, sb.length(), -1); assertEquals("aax--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 3, sb.length(), -1); assertEquals("aax--y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 4, sb.length(), -1); assertEquals("aaxa-ay-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 5, sb.length(), -1); assertEquals("aaxaa-y-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 6, sb.length(), -1); assertEquals("aaxaaaay-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 7, sb.length(), -1); assertEquals("aaxaaaay-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 8, sb.length(), -1); assertEquals("aaxaaaay-", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 9, sb.length(), -1); assertEquals("aaxaaaayaa", sb.toString()); sb = new TextStringBuilder("aaxaaaayaa"); sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 10, sb.length(), -1); assertEquals("aaxaaaayaa", sb.toString()); final TextStringBuilder builder = new TextStringBuilder("aaxaaaayaa"); assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 11, builder.length(), -1)); assertEquals("aaxaaaayaa", builder.toString()); builder.set("aaxaaaayaa"); assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", -1, builder.length(), -1)); assertEquals("aaxaaaayaa", builder.toString()); } @Test void testReplaceAll_char_char() { final TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replaceAll('x', 'y'); assertEquals("abcbccba", sb.toString()); sb.replaceAll('a', 'd'); assertEquals("dbcbccbd", sb.toString()); sb.replaceAll('b', 'e'); assertEquals("dececced", sb.toString()); sb.replaceAll('c', 'f'); assertEquals("defeffed", sb.toString()); sb.replaceAll('d', 'd'); assertEquals("defeffed", sb.toString()); } @Test void testReplaceAll_String_String() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replaceAll((String) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceAll((String) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll("", null); assertEquals("abcbccba", sb.toString()); sb.replaceAll("", "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll("x", "y"); assertEquals("abcbccba", sb.toString()); sb.replaceAll("a", "d"); assertEquals("dbcbccbd", sb.toString()); sb.replaceAll("d", null); assertEquals("bcbccb", sb.toString()); sb.replaceAll("cb", "-"); assertEquals("b-c-", sb.toString()); sb = new TextStringBuilder("abcba"); sb.replaceAll("b", "xbx"); assertEquals("axbxcxbxa", sb.toString()); sb = new TextStringBuilder("bb"); sb.replaceAll("b", "xbx"); assertEquals("xbxxbx", sb.toString()); } @Test void testReplaceAll_StringMatcher_String() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replaceAll((StringMatcher) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceAll((StringMatcher) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StringMatcherFactory.INSTANCE.noneMatcher(), null); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StringMatcherFactory.INSTANCE.noneMatcher(), "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('x'), "y"); assertEquals("abcbccba", sb.toString()); sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('a'), "d"); assertEquals("dbcbccbd", sb.toString()); sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('d'), null); assertEquals("bcbccb", sb.toString()); sb.replaceAll(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-"); assertEquals("b-c-", sb.toString()); sb = new TextStringBuilder("abcba"); sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx"); assertEquals("axbxcxbxa", sb.toString()); sb = new TextStringBuilder("bb"); sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx"); assertEquals("xbxxbx", sb.toString()); sb = new TextStringBuilder("A1-A2A3-A4"); sb.replaceAll(A_NUMBER_MATCHER, "***"); assertEquals("***-******-***", sb.toString()); sb = new TextStringBuilder("Dear X, hello X."); sb.replaceAll(StringMatcherFactory.INSTANCE.stringMatcher("X"), "012345678901234567"); assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString()); } @Test void testReplaceFirst_char_char() { final TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replaceFirst('x', 'y'); assertEquals("abcbccba", sb.toString()); sb.replaceFirst('a', 'd'); assertEquals("dbcbccba", sb.toString()); sb.replaceFirst('b', 'e'); assertEquals("decbccba", sb.toString()); sb.replaceFirst('c', 'f'); assertEquals("defbccba", sb.toString()); sb.replaceFirst('d', 'd'); assertEquals("defbccba", sb.toString()); } @Test void testReplaceFirst_String_String() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replaceFirst((String) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst((String) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("", null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("", "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("x", "y"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst("a", "d"); assertEquals("dbcbccba", sb.toString()); sb.replaceFirst("d", null); assertEquals("bcbccba", sb.toString()); sb.replaceFirst("cb", "-"); assertEquals("b-ccba", sb.toString()); sb = new TextStringBuilder("abcba"); sb.replaceFirst("b", "xbx"); assertEquals("axbxcba", sb.toString()); sb = new TextStringBuilder("bb"); sb.replaceFirst("b", "xbx"); assertEquals("xbxb", sb.toString()); } @Test void testReplaceFirst_StringMatcher_String() { TextStringBuilder sb = new TextStringBuilder("abcbccba"); sb.replaceFirst((StringMatcher) null, null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst((StringMatcher) null, "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StringMatcherFactory.INSTANCE.noneMatcher(), null); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StringMatcherFactory.INSTANCE.noneMatcher(), "anything"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('x'), "y"); assertEquals("abcbccba", sb.toString()); sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('a'), "d"); assertEquals("dbcbccba", sb.toString()); sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('d'), null); assertEquals("bcbccba", sb.toString()); sb.replaceFirst(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-"); assertEquals("b-ccba", sb.toString()); sb = new TextStringBuilder("abcba"); sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx"); assertEquals("axbxcba", sb.toString()); sb = new TextStringBuilder("bb"); sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx"); assertEquals("xbxb", sb.toString()); sb = new TextStringBuilder("A1-A2A3-A4"); sb.replaceFirst(A_NUMBER_MATCHER, "***"); assertEquals("***-A2A3-A4", sb.toString()); } @Test void testReverse() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals("", sb.reverse().toString()); sb.clear().append(true); assertEquals("eurt", sb.reverse().toString()); assertEquals("true", sb.reverse().toString()); } @Test void testRightString() { final TextStringBuilder sb = new TextStringBuilder("left right"); assertEquals("right", sb.rightString(5)); assertEquals("", sb.rightString(0)); assertEquals("", sb.rightString(-5)); assertEquals("left right", sb.rightString(15)); } @Test void testSetCharAt() { final TextStringBuilder sb = new TextStringBuilder(); assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(0, 'f')); assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(-1, 'f')); sb.append("foo"); sb.setCharAt(0, 'b'); sb.setCharAt(1, 'a'); sb.setCharAt(2, 'r'); assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(3, '!')); assertEquals("bar", sb.toString()); } @Test void testSetLength() { final TextStringBuilder sb = new TextStringBuilder(); sb.append("Hello"); sb.setLength(2); // shorten assertEquals("He", sb.toString()); sb.setLength(2); // no change assertEquals("He", sb.toString()); sb.setLength(3); // lengthen assertEquals("He\0", sb.toString()); assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1)); } @Test void testSize() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(0, sb.size()); sb.append("Hello"); assertEquals(5, sb.size()); } @Test void testStartsWith() { final TextStringBuilder sb = new TextStringBuilder(); assertFalse(sb.startsWith("a")); assertFalse(sb.startsWith(null)); assertTrue(sb.startsWith("")); sb.append("abc"); assertTrue(sb.startsWith("a")); assertTrue(sb.startsWith("ab")); assertTrue(sb.startsWith("abc")); assertFalse(sb.startsWith("cba")); } @Test void testSubSequenceIntInt() { final TextStringBuilder sb = new TextStringBuilder("hello goodbye"); // Start index is negative assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(-1, 5)); // End index is negative assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, -1)); // End index greater than length() assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, sb.length() + 1)); // Start index greater then end index assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(3, 2)); // Normal cases assertEquals("hello", sb.subSequence(0, 5)); assertEquals("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6)); assertEquals("goodbye", sb.subSequence(6, 13)); assertEquals("hello goodbye".subSequence(6, 13), sb.subSequence(6, 13)); } @Test void testSubstringInt() { final TextStringBuilder sb = new TextStringBuilder("hello goodbye"); assertEquals("goodbye", sb.substring(6)); assertEquals("hello goodbye".substring(6), sb.substring(6)); assertEquals("hello goodbye", sb.substring(0)); assertEquals("hello goodbye".substring(0), sb.substring(0)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15)); } @Test void testSubstringIntInt() { final TextStringBuilder sb = new TextStringBuilder("hello goodbye"); assertEquals("hello", sb.substring(0, 5)); assertEquals("hello goodbye".substring(0, 6), sb.substring(0, 6)); assertEquals("goodbye", sb.substring(6, 13)); assertEquals("hello goodbye".substring(6, 13), sb.substring(6, 13)); assertEquals("goodbye", sb.substring(6, 20)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1, 5)); assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15, 20)); } @Test void testToCharArray() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(0, sb.toCharArray().length); char[] a = sb.toCharArray(); assertNotNull(a, "toCharArray() result is null"); assertEquals(0, a.length, "toCharArray() result is too large"); sb.append("junit"); a = sb.toCharArray(); assertEquals(5, a.length, "toCharArray() result incorrect length"); assertArrayEquals("junit".toCharArray(), a, "toCharArray() result does not match"); } @Test void testToCharArrayIntInt() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(0, sb.toCharArray(0, 0).length); sb.append("junit"); char[] a = sb.toCharArray(0, 20); // too large test assertEquals(5, a.length, "toCharArray(int,int) result incorrect length"); assertArrayEquals("junit".toCharArray(), a, "toCharArray(int,int) result does not match"); a = sb.toCharArray(0, 4); assertEquals(4, a.length, "toCharArray(int,int) result incorrect length"); assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match"); a = sb.toCharArray(0, 4); assertEquals(4, a.length, "toCharArray(int,int) result incorrect length"); assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match"); a = sb.toCharArray(0, 1); assertNotNull(a, "toCharArray(int,int) result is null"); assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(-1, 5)); assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(6, 5)); } @Test void testToString() { final TextStringBuilder sb = new TextStringBuilder("abc"); assertEquals("abc", sb.toString()); } @Test void testToStringBuffer() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString()); sb.append("junit"); assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString()); } @Test void testToStringBuilder() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString()); sb.append("junit"); assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString()); } @Test void testTrim() { final TextStringBuilder sb = new TextStringBuilder(); assertEquals("", sb.reverse().toString()); sb.set(" \u0000 "); assertEquals("", sb.trim().toString()); sb.set(" \u0000 a b c"); assertEquals("a b c", sb.trim().toString()); sb.set("a b c \u0000 "); assertEquals("a b c", sb.trim().toString()); sb.set(" \u0000 a b c \u0000 "); assertEquals("a b c", sb.trim().toString()); sb.set("a b c"); assertEquals("a b c", sb.trim().toString()); } @Test void testWrap_CharArray() { assertThrows(NullPointerException.class, () -> TextStringBuilder.wrap(null)); // final TextStringBuilder initEmpty = TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY); assertEquals(0, initEmpty.size()); assertEquals(0, initEmpty.length()); initEmpty.append('a'); assertEquals(1, initEmpty.size()); assertEquals(1, initEmpty.length()); // final char[] test = "abc".toCharArray(); final TextStringBuilder builder = TextStringBuilder.wrap(test); assertArrayEquals(test, builder.getBuffer()); assertEquals(test.length, builder.length()); assertEquals(test.length, builder.size()); assertFalse(builder.isReallocated()); builder.ensureCapacity(builder.capacity() * 2); assertFalse(Arrays.equals(test, builder.getBuffer())); assertTrue(builder.isReallocated()); } private void testWrap_CharArray_Int(final String test, final int expectedLen) { final char[] input = "abc".toCharArray(); final TextStringBuilder builder = TextStringBuilder.wrap(input, expectedLen); assertArrayEquals(input, builder.getBuffer()); assertEquals(expectedLen, builder.length()); assertEquals(expectedLen, builder.size()); assertFalse(builder.isReallocated()); builder.ensureCapacity(builder.capacity() * 2); assertFalse(Arrays.equals(input, builder.getBuffer())); assertTrue(builder.isReallocated()); } @Test void testWrap_CharArray_Int_0() { testWrap_CharArray_Int("abc", 0); } @Test void testWrap_CharArray_Int_1() { testWrap_CharArray_Int("abc", 1); } @Test void testWrap_CharArray_Int_2() { testWrap_CharArray_Int("abc", 2); } @Test void testWrap_CharArray_Int_3() { testWrap_CharArray_Int("abc", 3); } @Test void testWrap_CharArray_Int_Empty_0() { final TextStringBuilder initEmpty = TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY, 0); assertEquals(0, initEmpty.size()); assertEquals(0, initEmpty.length()); initEmpty.append('a'); assertEquals(1, initEmpty.size()); assertEquals(1, initEmpty.length()); } @Test void testWrap_CharArray_Int_Exceptions() { assertThrows(NullPointerException.class, () -> TextStringBuilder.wrap(null, 0)); assertThrows(IllegalArgumentException.class, () -> TextStringBuilder.wrap("abc".toCharArray(), -1)); assertThrows(IllegalArgumentException.class, () -> TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY, 1)); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/WordUtilsTest.java000066400000000000000000000671001511432740600322520ustar00rootroot00000000000000/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.stream.IntStream; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; /** * Tests {@link WordUtils}. */ class WordUtilsTest { private static final String WHITESPACE = IntStream.rangeClosed(Character.MIN_CODE_POINT, Character.MAX_CODE_POINT).filter(Character::isWhitespace) .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString(); @Test void testAbbreviateForLowerThanMinusOneValues() { assertThrows(IllegalArgumentException.class, () -> WordUtils.abbreviate("01 23 45 67 89", 9, -10, null)); } @Test void testAbbreviateForLowerValue() { assertEquals("012", WordUtils.abbreviate("012 3456789", 0, 5, null)); assertEquals("01234", WordUtils.abbreviate("01234 56789", 5, 10, null)); assertEquals("01 23 45 67", WordUtils.abbreviate("01 23 45 67 89", 9, -1, null)); assertEquals("01 23 45 6", WordUtils.abbreviate("01 23 45 67 89", 9, 10, null)); assertEquals("0123456789", WordUtils.abbreviate("0123456789", 15, 20, null)); } @Test void testAbbreviateForLowerValueAndAppendedString() { assertEquals("012", WordUtils.abbreviate("012 3456789", 0, 5, null)); assertEquals("01234-", WordUtils.abbreviate("01234 56789", 5, 10, "-")); assertEquals("01 23 45 67abc", WordUtils.abbreviate("01 23 45 67 89", 9, -1, "abc")); assertEquals("01 23 45 6", WordUtils.abbreviate("01 23 45 67 89", 9, 10, "")); } @Test void testAbbreviateForNullAndEmptyString() { assertNull(WordUtils.abbreviate(null, 1, -1, "")); assertEquals(StringUtils.EMPTY, WordUtils.abbreviate("", 1, -1, "")); assertEquals("", WordUtils.abbreviate("0123456790", 0, 0, "")); assertEquals("", WordUtils.abbreviate(" 0123456790", 0, -1, "")); } @Test void testAbbreviateForUpperLimit() { assertEquals("01234", WordUtils.abbreviate("0123456789", 0, 5, "")); assertEquals("012", WordUtils.abbreviate("012 3456789", 2, 5, "")); assertEquals("0123456789", WordUtils.abbreviate("0123456789", 0, -1, "")); } @Test void testAbbreviateForUpperLimitAndAppendedString() { assertEquals("01234-", WordUtils.abbreviate("0123456789", 0, 5, "-")); assertEquals("012", WordUtils.abbreviate("012 3456789", 2, 5, null)); assertEquals("0123456789", WordUtils.abbreviate("0123456789", 0, -1, "")); } @Test void testAbbreviateUpperLessThanLowerValues() { assertThrows(IllegalArgumentException.class, () -> WordUtils.abbreviate("0123456789", 5, 2, "")); } @Test void testCapitalize_String() { assertNull(WordUtils.capitalize(null)); assertEquals("", WordUtils.capitalize("")); assertEquals(" ", WordUtils.capitalize(" ")); assertEquals("I", WordUtils.capitalize("I")); assertEquals("I", WordUtils.capitalize("i")); assertEquals("I Am Here 123", WordUtils.capitalize("i am here 123")); assertEquals("I Am Here 123", WordUtils.capitalize("I Am Here 123")); assertEquals("I Am HERE 123", WordUtils.capitalize("i am HERE 123")); assertEquals("I AM HERE 123", WordUtils.capitalize("I AM HERE 123")); } @Test void testCapitalizeFully_String() { assertNull(WordUtils.capitalizeFully(null)); assertEquals("", WordUtils.capitalizeFully("")); assertEquals(" ", WordUtils.capitalizeFully(" ")); assertEquals("I", WordUtils.capitalizeFully("I")); assertEquals("I", WordUtils.capitalizeFully("i")); assertEquals("I Am Here 123", WordUtils.capitalizeFully("i am here 123")); assertEquals("I Am Here 123", WordUtils.capitalizeFully("I Am Here 123")); assertEquals("I Am Here 123", WordUtils.capitalizeFully("i am HERE 123")); assertEquals("I Am Here 123", WordUtils.capitalizeFully("I AM HERE 123")); assertEquals("Alphabet", WordUtils.capitalizeFully("alphabet")); // single word assertEquals("A\tB\nC D", WordUtils.capitalizeFully("a\tb\nc d")); assertEquals("And \tBut \nCleat Dome", WordUtils.capitalizeFully("and \tbut \ncleat dome")); // All whitespace assertEquals(WHITESPACE, WordUtils.capitalizeFully(WHITESPACE)); assertEquals("A" + WHITESPACE + "B", WordUtils.capitalizeFully("a" + WHITESPACE + "b")); } @Test void testCapitalizeFully_Text88() { assertEquals("I am fine now", WordUtils.capitalizeFully("i am fine now", new char[] {})); } @Test void testCapitalizeFullyWithDelimiters_String() { assertNull(WordUtils.capitalizeFully(null, null)); assertEquals("", WordUtils.capitalizeFully("", ArrayUtils.EMPTY_CHAR_ARRAY)); assertEquals(" ", WordUtils.capitalizeFully(" ", ArrayUtils.EMPTY_CHAR_ARRAY)); char[] chars = { '-', '+', ' ', '@' }; assertEquals("I", WordUtils.capitalizeFully("I", chars)); assertEquals("I", WordUtils.capitalizeFully("i", chars)); assertEquals("I-Am Here+123", WordUtils.capitalizeFully("i-am here+123", chars)); assertEquals("I Am+Here-123", WordUtils.capitalizeFully("I Am+Here-123", chars)); assertEquals("I+Am-Here 123", WordUtils.capitalizeFully("i+am-HERE 123", chars)); assertEquals("I-Am Here+123", WordUtils.capitalizeFully("I-AM HERE+123", chars)); chars = new char[] { '.' }; assertEquals("I am.Fine", WordUtils.capitalizeFully("i aM.fine", chars)); assertEquals("I Am.fine", WordUtils.capitalizeFully("i am.fine", null)); assertEquals("Alphabet", WordUtils.capitalizeFully("alphabet", null)); // single word assertEquals("Alphabet", WordUtils.capitalizeFully("alphabet", new char[] { '!' })); // no matching delim } @Test void testCapitalizeWithDelimiters_String() { assertNull(WordUtils.capitalize(null, null)); assertEquals("", WordUtils.capitalize("", ArrayUtils.EMPTY_CHAR_ARRAY)); assertEquals(" ", WordUtils.capitalize(" ", ArrayUtils.EMPTY_CHAR_ARRAY)); char[] chars = { '-', '+', ' ', '@' }; assertEquals("I", WordUtils.capitalize("I", chars)); assertEquals("I", WordUtils.capitalize("i", chars)); assertEquals("I-Am Here+123", WordUtils.capitalize("i-am here+123", chars)); assertEquals("I Am+Here-123", WordUtils.capitalize("I Am+Here-123", chars)); assertEquals("I+Am-HERE 123", WordUtils.capitalize("i+am-HERE 123", chars)); assertEquals("I-AM HERE+123", WordUtils.capitalize("I-AM HERE+123", chars)); chars = new char[] { '.' }; assertEquals("I aM.Fine", WordUtils.capitalize("i aM.fine", chars)); assertEquals("I Am.fine", WordUtils.capitalize("i am.fine", null)); } @Test void testConstructor() { assertNotNull(new WordUtils()); final Constructor[] cons = WordUtils.class.getDeclaredConstructors(); assertEquals(1, cons.length); assertTrue(Modifier.isPublic(cons[0].getModifiers())); assertTrue(Modifier.isPublic(WordUtils.class.getModifiers())); assertFalse(Modifier.isFinal(WordUtils.class.getModifiers())); } @Test void testContainsAllWords_StringString() { assertFalse(WordUtils.containsAllWords(null, (String) null)); assertFalse(WordUtils.containsAllWords(null, "")); assertFalse(WordUtils.containsAllWords(null, "ab")); assertFalse(WordUtils.containsAllWords("", (String) null)); assertFalse(WordUtils.containsAllWords("", "")); assertFalse(WordUtils.containsAllWords("", "ab")); assertFalse(WordUtils.containsAllWords("foo", (String) null)); assertFalse(WordUtils.containsAllWords("bar", "")); assertFalse(WordUtils.containsAllWords("zzabyycdxx", "by")); assertTrue(WordUtils.containsAllWords("lorem ipsum dolor sit amet", "ipsum", "lorem", "dolor")); assertFalse(WordUtils.containsAllWords("lorem ipsum dolor sit amet", "ipsum", null, "lorem", "dolor")); assertFalse(WordUtils.containsAllWords("lorem ipsum null dolor sit amet", "ipsum", null, "lorem", "dolor")); assertFalse(WordUtils.containsAllWords("ab", "b")); assertFalse(WordUtils.containsAllWords("ab", "z")); assertFalse(WordUtils.containsAllWords("ab", "[")); assertFalse(WordUtils.containsAllWords("ab", "]")); assertFalse(WordUtils.containsAllWords("ab", "*")); assertTrue(WordUtils.containsAllWords("ab x", "ab", "x")); } @Test void testContainsAllWordsWithNull() { assertFalse(WordUtils.containsAllWords("M", (CharSequence) null)); } @Test void testInitials_String() { assertNull(WordUtils.initials(null)); assertEquals("", WordUtils.initials("")); assertEquals("", WordUtils.initials(" ")); assertEquals("I", WordUtils.initials("I")); assertEquals("i", WordUtils.initials("i")); assertEquals("BJL", WordUtils.initials("Ben John Lee")); assertEquals("BJL", WordUtils.initials(" Ben \n John\tLee\t")); assertEquals("BJ", WordUtils.initials("Ben J.Lee")); assertEquals("BJ.L", WordUtils.initials(" Ben John . Lee")); assertEquals("iah1", WordUtils.initials("i am here 123")); } @Test void testInitials_String_charArray() { char[] array = null; assertNull(WordUtils.initials(null, array)); assertEquals("", WordUtils.initials("", array)); assertEquals("", WordUtils.initials(" ", array)); assertEquals("I", WordUtils.initials("I", array)); assertEquals("i", WordUtils.initials("i", array)); assertEquals("S", WordUtils.initials("SJC", array)); assertEquals("BJL", WordUtils.initials("Ben John Lee", array)); assertEquals("BJL", WordUtils.initials(" Ben \n John\tLee\t", array)); assertEquals("BJ", WordUtils.initials("Ben J.Lee", array)); assertEquals("BJ.L", WordUtils.initials(" Ben John . Lee", array)); assertEquals("KO", WordUtils.initials("Kay O'Murphy", array)); assertEquals("iah1", WordUtils.initials("i am here 123", array)); array = ArrayUtils.EMPTY_CHAR_ARRAY; assertNull(WordUtils.initials(null, array)); assertEquals("", WordUtils.initials("", array)); assertEquals("", WordUtils.initials(" ", array)); assertEquals("", WordUtils.initials("I", array)); assertEquals("", WordUtils.initials("i", array)); assertEquals("", WordUtils.initials("SJC", array)); assertEquals("", WordUtils.initials("Ben John Lee", array)); assertEquals("", WordUtils.initials(" Ben \n John\tLee\t", array)); assertEquals("", WordUtils.initials("Ben J.Lee", array)); assertEquals("", WordUtils.initials(" Ben John . Lee", array)); assertEquals("", WordUtils.initials("Kay O'Murphy", array)); assertEquals("", WordUtils.initials("i am here 123", array)); array = " ".toCharArray(); assertNull(WordUtils.initials(null, array)); assertEquals("", WordUtils.initials("", array)); assertEquals("", WordUtils.initials(" ", array)); assertEquals("I", WordUtils.initials("I", array)); assertEquals("i", WordUtils.initials("i", array)); assertEquals("S", WordUtils.initials("SJC", array)); assertEquals("BJL", WordUtils.initials("Ben John Lee", array)); assertEquals("BJ", WordUtils.initials("Ben J.Lee", array)); assertEquals("B\nJ", WordUtils.initials(" Ben \n John\tLee\t", array)); assertEquals("BJ.L", WordUtils.initials(" Ben John . Lee", array)); assertEquals("KO", WordUtils.initials("Kay O'Murphy", array)); assertEquals("iah1", WordUtils.initials("i am here 123", array)); array = " .".toCharArray(); assertNull(WordUtils.initials(null, array)); assertEquals("", WordUtils.initials("", array)); assertEquals("", WordUtils.initials(" ", array)); assertEquals("I", WordUtils.initials("I", array)); assertEquals("i", WordUtils.initials("i", array)); assertEquals("S", WordUtils.initials("SJC", array)); assertEquals("BJL", WordUtils.initials("Ben John Lee", array)); assertEquals("BJL", WordUtils.initials("Ben J.Lee", array)); assertEquals("BJL", WordUtils.initials(" Ben John . Lee", array)); assertEquals("KO", WordUtils.initials("Kay O'Murphy", array)); assertEquals("iah1", WordUtils.initials("i am here 123", array)); array = " .'".toCharArray(); assertNull(WordUtils.initials(null, array)); assertEquals("", WordUtils.initials("", array)); assertEquals("", WordUtils.initials(" ", array)); assertEquals("I", WordUtils.initials("I", array)); assertEquals("i", WordUtils.initials("i", array)); assertEquals("S", WordUtils.initials("SJC", array)); assertEquals("BJL", WordUtils.initials("Ben John Lee", array)); assertEquals("BJL", WordUtils.initials("Ben J.Lee", array)); assertEquals("BJL", WordUtils.initials(" Ben John . Lee", array)); assertEquals("KOM", WordUtils.initials("Kay O'Murphy", array)); assertEquals("iah1", WordUtils.initials("i am here 123", array)); array = "SIJo1".toCharArray(); assertNull(WordUtils.initials(null, array)); assertEquals("", WordUtils.initials("", array)); assertEquals(" ", WordUtils.initials(" ", array)); assertEquals("", WordUtils.initials("I", array)); assertEquals("i", WordUtils.initials("i", array)); assertEquals("C", WordUtils.initials("SJC", array)); assertEquals("Bh", WordUtils.initials("Ben John Lee", array)); assertEquals("B.", WordUtils.initials("Ben J.Lee", array)); assertEquals(" h", WordUtils.initials(" Ben John . Lee", array)); assertEquals("K", WordUtils.initials("Kay O'Murphy", array)); assertEquals("i2", WordUtils.initials("i am here 123", array)); } @Test void testInitialsSurrogatePairs() { // Tests with space as default delimiter assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00\uD800\uDF01 \uD800\uDF02\uD800\uDF03")); assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00\uD800\uDF01 \uD800\uDF02\uD800\uDF03", null)); assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00 \uD800\uDF02 ", null)); // Tests with UTF-16 as delimiters assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00\uD800\uDF01.\uD800\uDF02\uD800\uDF03", new char[] { '.' })); assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00\uD800\uDF01A\uD800\uDF02\uD800\uDF03", new char[] { 'A' })); // Tests with UTF-32 as delimiters assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00\uD800\uDF01\uD800\uDF14\uD800\uDF02\uD800\uDF03", new char[] { '\uD800', '\uDF14' })); assertEquals("\uD800\uDF00\uD800\uDF02", WordUtils.initials("\uD800\uDF00\uD800\uDF01\uD800\uDF14\uD800\uDF18\uD800\uDF02\uD800\uDF03", new char[] { '\uD800', '\uDF14', '\uD800', '\uDF18' })); } @Test void testLANG1292() { // Prior to fix, this was throwing StringIndexOutOfBoundsException WordUtils.wrap("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 70); } @Test void testLANG673() { assertEquals("01", WordUtils.abbreviate("01 23 45 67 89", 0, 40, "")); assertEquals("01 23 45 67", WordUtils.abbreviate("01 23 45 67 89", 10, 40, "")); assertEquals("01 23 45 67 89", WordUtils.abbreviate("01 23 45 67 89", 40, 40, "")); } @Test void testSwapCase_String() { assertNull(WordUtils.swapCase(null)); assertEquals("", WordUtils.swapCase("")); assertEquals(" ", WordUtils.swapCase(" ")); assertEquals("i", WordUtils.swapCase("I")); assertEquals("I", WordUtils.swapCase("i")); assertEquals("I AM HERE 123", WordUtils.swapCase("i am here 123")); assertEquals("i aM hERE 123", WordUtils.swapCase("I Am Here 123")); assertEquals("I AM here 123", WordUtils.swapCase("i am HERE 123")); assertEquals("i am here 123", WordUtils.swapCase("I AM HERE 123")); final String test = "This String contains a TitleCase character: \u01C8"; final String expect = "tHIS sTRING CONTAINS A tITLEcASE CHARACTER: \u01C9"; assertEquals(expect, WordUtils.swapCase(test)); } @Test void testText123() throws Exception { // Prior to fix, this was throwing StringIndexOutOfBoundsException WordUtils.wrap("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Integer.MAX_VALUE); } @Test void testUncapitalize_String() { assertNull(WordUtils.uncapitalize(null)); assertEquals("", WordUtils.uncapitalize("")); assertEquals(" ", WordUtils.uncapitalize(" ")); assertEquals("i", WordUtils.uncapitalize("I")); assertEquals("i", WordUtils.uncapitalize("i")); assertEquals("i am here 123", WordUtils.uncapitalize("i am here 123")); assertEquals("i am here 123", WordUtils.uncapitalize("I Am Here 123")); assertEquals("i am hERE 123", WordUtils.uncapitalize("i am HERE 123")); assertEquals("i aM hERE 123", WordUtils.uncapitalize("I AM HERE 123")); assertEquals("a\tb\nc d", WordUtils.uncapitalize("A\tB\nC D")); assertEquals("and \tbut \ncLEAT dome", WordUtils.uncapitalize("And \tBut \nCLEAT Dome")); // All whitespace assertEquals(WHITESPACE, WordUtils.capitalizeFully(WHITESPACE)); assertEquals("A" + WHITESPACE + "B", WordUtils.capitalizeFully("a" + WHITESPACE + "b")); } @Test void testUnCapitalize_Text88() { assertEquals("i am fine now", WordUtils.uncapitalize("I am fine now", new char[] {})); } @Test void testUncapitalizeWithDelimiters_String() { assertNull(WordUtils.uncapitalize(null, null)); assertEquals("", WordUtils.uncapitalize("", ArrayUtils.EMPTY_CHAR_ARRAY)); assertEquals(" ", WordUtils.uncapitalize(" ", ArrayUtils.EMPTY_CHAR_ARRAY)); char[] chars = { '-', '+', ' ', '@' }; assertEquals("i", WordUtils.uncapitalize("I", chars)); assertEquals("i", WordUtils.uncapitalize("i", chars)); assertEquals("i am-here+123", WordUtils.uncapitalize("i am-here+123", chars)); assertEquals("i+am here-123", WordUtils.uncapitalize("I+Am Here-123", chars)); assertEquals("i-am+hERE 123", WordUtils.uncapitalize("i-am+HERE 123", chars)); assertEquals("i aM-hERE+123", WordUtils.uncapitalize("I AM-HERE+123", chars)); chars = new char[] { '.' }; assertEquals("i AM.fINE", WordUtils.uncapitalize("I AM.FINE", chars)); assertEquals("i aM.FINE", WordUtils.uncapitalize("I AM.FINE", null)); } @Test void testWrap_StringInt() { assertNull(WordUtils.wrap(null, 20)); assertNull(WordUtils.wrap(null, -1)); assertEquals("", WordUtils.wrap("", 20)); assertEquals("", WordUtils.wrap("", -1)); // normal final String systemNewLine = System.lineSeparator(); String input = "Here is one line of text that is going to be wrapped after 20 columns."; String expected = "Here is one line of" + systemNewLine + "text that is going" + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."; assertEquals(expected, WordUtils.wrap(input, 20)); // long word at end input = "Click here to jump to the commons website - https://commons.apache.org"; expected = "Click here to jump" + systemNewLine + "to the commons" + systemNewLine + "website -" + systemNewLine + "https://commons.apache.org"; assertEquals(expected, WordUtils.wrap(input, 20)); // long word in middle input = "Click here, https://commons.apache.org, to jump to the commons website"; expected = "Click here," + systemNewLine + "https://commons.apache.org," + systemNewLine + "to jump to the" + systemNewLine + "commons website"; assertEquals(expected, WordUtils.wrap(input, 20)); // leading spaces on a new line are stripped // trailing spaces are not stripped input = "word1 word2 word3"; expected = "word1 " + systemNewLine + "word2 " + systemNewLine + "word3"; assertEquals(expected, WordUtils.wrap(input, 7)); } @Test void testWrap_StringIntStringBoolean() { assertNull(WordUtils.wrap(null, 20, "\n", false)); assertNull(WordUtils.wrap(null, 20, "\n", true)); assertNull(WordUtils.wrap(null, 20, null, true)); assertNull(WordUtils.wrap(null, 20, null, false)); assertNull(WordUtils.wrap(null, -1, null, true)); assertNull(WordUtils.wrap(null, -1, null, false)); assertEquals("", WordUtils.wrap("", 20, "\n", false)); assertEquals("", WordUtils.wrap("", 20, "\n", true)); assertEquals("", WordUtils.wrap("", 20, null, false)); assertEquals("", WordUtils.wrap("", 20, null, true)); assertEquals("", WordUtils.wrap("", -1, null, false)); assertEquals("", WordUtils.wrap("", -1, null, true)); // normal String input = "Here is one line of text that is going to be wrapped after 20 columns."; String expected = "Here is one line of\ntext that is going\nto be wrapped after\n20 columns."; assertEquals(expected, WordUtils.wrap(input, 20, "\n", false)); assertEquals(expected, WordUtils.wrap(input, 20, "\n", true)); // unusual newline char input = "Here is one line of text that is going to be wrapped after 20 columns."; expected = "Here is one line of
text that is going
to be wrapped after
20 columns."; assertEquals(expected, WordUtils.wrap(input, 20, "
", false)); assertEquals(expected, WordUtils.wrap(input, 20, "
", true)); // short line length input = "Here is one line"; expected = "Here\nis one\nline"; assertEquals(expected, WordUtils.wrap(input, 6, "\n", false)); expected = "Here\nis\none\nline"; assertEquals(expected, WordUtils.wrap(input, 2, "\n", false)); assertEquals(expected, WordUtils.wrap(input, -1, "\n", false)); // system newline char final String systemNewLine = System.lineSeparator(); input = "Here is one line of text that is going to be wrapped after 20 columns."; expected = "Here is one line of" + systemNewLine + "text that is going" + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."; assertEquals(expected, WordUtils.wrap(input, 20, null, false)); assertEquals(expected, WordUtils.wrap(input, 20, null, true)); // with extra spaces input = " Here: is one line of text that is going to be wrapped after 20 columns."; expected = "Here: is one line\nof text that is \ngoing to be \nwrapped after 20 \ncolumns."; assertEquals(expected, WordUtils.wrap(input, 20, "\n", false)); assertEquals(expected, WordUtils.wrap(input, 20, "\n", true)); // with tab input = "Here is\tone line of text that is going to be wrapped after 20 columns."; expected = "Here is\tone line of\ntext that is going\nto be wrapped after\n20 columns."; assertEquals(expected, WordUtils.wrap(input, 20, "\n", false)); assertEquals(expected, WordUtils.wrap(input, 20, "\n", true)); // with tab at wrapColumn input = "Here is one line of\ttext that is going to be wrapped after 20 columns."; expected = "Here is one line\nof\ttext that is\ngoing to be wrapped\nafter 20 columns."; assertEquals(expected, WordUtils.wrap(input, 20, "\n", false)); assertEquals(expected, WordUtils.wrap(input, 20, "\n", true)); // difference because of long word input = "Click here to jump to the commons website - https://commons.apache.org"; expected = "Click here to jump\nto the commons\nwebsite -\nhttps://commons.apache.org"; assertEquals(expected, WordUtils.wrap(input, 20, "\n", false)); expected = "Click here to jump\nto the commons\nwebsite -\nhttps://commons.apac\nhe.org"; assertEquals(expected, WordUtils.wrap(input, 20, "\n", true)); // difference because of long word in middle input = "Click here, https://commons.apache.org, to jump to the commons website"; expected = "Click here,\nhttps://commons.apache.org,\nto jump to the\ncommons website"; assertEquals(expected, WordUtils.wrap(input, 20, "\n", false)); expected = "Click here,\nhttps://commons.apac\nhe.org, to jump to\nthe commons website"; assertEquals(expected, WordUtils.wrap(input, 20, "\n", true)); } @Test void testWrap_StringIntStringBooleanString() { // no changes test String input = "flammable/inflammable"; String expected = "flammable/inflammable"; assertEquals(expected, WordUtils.wrap(input, 30, "\n", false, "/")); // wrap on / and small width expected = "flammable\ninflammable"; assertEquals(expected, WordUtils.wrap(input, 2, "\n", false, "/")); // wrap long words on / 1 expected = "flammable\ninflammab\nle"; assertEquals(expected, WordUtils.wrap(input, 9, "\n", true, "/")); // wrap long words on / 2 expected = "flammable\ninflammable"; assertEquals(expected, WordUtils.wrap(input, 15, "\n", true, "/")); // wrap long words on / 3 input = "flammableinflammable"; expected = "flammableinflam\nmable"; assertEquals(expected, WordUtils.wrap(input, 15, "\n", true, "/")); } @Test void testWrapAtMiddleTwice() { assertEquals("abcdef\n\nabcdef", WordUtils.wrap("abcdefggabcdef", 2, "\n", false, "(?=g)")); } @Test void testWrapAtStartAndEnd() { assertEquals("\nabcdefabcdef\n", WordUtils.wrap("nabcdefabcdefn", 2, "\n", false, "(?=n)")); } @Test void testWrapWithMultipleRegexMatchOfLength0() { assertEquals("abc\ndefabc\ndef", WordUtils.wrap("abcdefabcdef", 2, "\n", false, "(?=d)")); } @Test void testWrapWithRegexMatchOfLength0() { assertEquals("abc\ndef", WordUtils.wrap("abcdef", 2, "\n", false, "(?=d)")); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/diff/000077500000000000000000000000001511432740600275175ustar00rootroot00000000000000ReplacementsFinderTest.java000066400000000000000000000067401511432740600347240ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/diff/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.diff; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; /** * Tests for the ReplacementsFinder. */ class ReplacementsFinderTest { // Helper ReplacementsHandler implementation for testing private static final class SimpleHandler implements ReplacementsHandler { private int skipped; private final List from; private final List to; SimpleHandler() { skipped = 0; from = new ArrayList<>(); to = new ArrayList<>(); } public List getFrom() { return from; } public int getSkipped() { return skipped; } public List getTo() { return to; } @Override public void handleReplacement(final int skipped, final List from, final List to) { this.skipped += skipped; this.from.addAll(from); this.to.addAll(to); } } public static Stream parameters() { return Stream.of(Arguments.of("branco", "blanco", 1, new Character[] {'r'}, new Character[] {'l'}), Arguments.of("test the blocks before you use it", "try the blocks before you put it", 25, new Character[] {'e', 's', 't', 's', 'e'}, new Character[] {'r', 'y', 'p', 't'})); } private SimpleHandler handler; @BeforeEach public void setUp() { handler = new SimpleHandler(); } @ParameterizedTest @MethodSource("parameters") void testReplacementsHandler(final String left, final String right, final int skipped, final Character[] from, final Character[] to) { final StringsComparator sc = new StringsComparator(left, right); final ReplacementsFinder replacementFinder = new ReplacementsFinder<>(handler); sc.getScript().visit(replacementFinder); assertEquals(skipped, handler.getSkipped(), "Skipped characters do not match"); assertArrayEquals(handler.getFrom().toArray(ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY), from, "From characters do not match"); assertArrayEquals(to, handler.getTo().toArray(ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY), "To characters do not match"); } } StringsComparatorTest.java000066400000000000000000000073201511432740600346260ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/diff/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.diff; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests for the StringsComparator. */ class StringsComparatorTest { private static final class ExecutionVisitor implements CommandVisitor { private final StringBuilder v; ExecutionVisitor() { v = new StringBuilder(); } public String getString() { return v.toString(); } @Override public void visitDeleteCommand(final T object) { // noop } @Override public void visitInsertCommand(final T object) { v.append(object); } @Override public void visitKeepCommand(final T object) { v.append(object); } } private List before; private List after; private int[] length; private int[] lcs; @BeforeEach public void setUp() { before = Arrays.asList( "bottle", "nematode knowledge", "", "aa", "prefixed string", "ABCABBA", "glop glop", "coq", "spider-man"); after = Arrays.asList( "noodle", "empty bottle", "", "C", "prefix", "CBABAC", "pas glop pas glop", "ane", "klingon"); length = new int[] { 6, 16, 0, 3, 9, 5, 8, 6, 13 }; lcs = new int[] { 3, 7, 0, 0, 6, 4, 9, 0, 2 }; } @AfterEach public void tearDown() { before = null; after = null; length = null; } @Test void testExecution() { for (int i = 0; i < before.size(); ++i) { final ExecutionVisitor ev = new ExecutionVisitor<>(); new StringsComparator(before.get(i), after.get(i)).getScript().visit(ev); assertEquals(after.get(i), ev.getString()); } } @Test void testLength() { for (int i = 0; i < before.size(); ++i) { final StringsComparator comparator = new StringsComparator(before.get(i), after.get(i)); assertEquals(length[i], comparator.getScript().getModifications()); } } @Test void testLongestCommonSubsequence() { for (int i = 0; i < before.size(); ++i) { final StringsComparator comparator = new StringsComparator(before.get(i), after.get(i)); assertEquals(lcs[i], comparator.getScript().getLCSLength()); } } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/io/000077500000000000000000000000001511432740600272165ustar00rootroot00000000000000StringSubstitutorFilterReaderTest.java000066400000000000000000000307561511432740600367040ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/io/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.io; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.util.Arrays; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.NullReader; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringSubstitutor; import org.apache.commons.text.StringSubstitutorTest; import org.junit.jupiter.api.Test; /** * Tests {@link StringSubstitutorReader}. */ class StringSubstitutorFilterReaderTest extends StringSubstitutorTest { private StringSubstitutorReader createReader(final StringSubstitutor substitutor, final String template) { return new StringSubstitutorReader(new StringReader(template), substitutor); } @Override protected void doTestNoReplace(final StringSubstitutor substitutor, final String replaceTemplate) throws IOException { super.doTestNoReplace(substitutor, replaceTemplate); doTestNoReplaceInSteps(replaceTemplate, substitutor); } private void doTestNoReplaceInSteps(final String replaceTemplate, final StringSubstitutor substitutor) throws IOException { doTestReplaceInCharSteps(substitutor, replaceTemplate, replaceTemplate, false); final int minTargetSize = 1; int maxTargetSize = 1024 * 8; for (int targetSize = minTargetSize; targetSize <= maxTargetSize; targetSize++) { doTestReplaceInCharArraySteps(substitutor, replaceTemplate, replaceTemplate, false, targetSize); } maxTargetSize = 400; for (int targetSize = minTargetSize; targetSize <= maxTargetSize; targetSize++) { for (int targetIndex = 0; targetIndex < targetSize; targetIndex++) { doTestReplaceInCharArrayAtSteps(substitutor, replaceTemplate, replaceTemplate, false, targetIndex, targetSize); } } } @Override protected void doTestReplace(final StringSubstitutor sub, final String expectedResult, final String replaceTemplate, final boolean substring) throws IOException { doTestReplaceInCharSteps(sub, expectedResult, replaceTemplate, substring); super.doTestReplace(sub, expectedResult, replaceTemplate, substring); } private void doTestReplaceInCharArrayAtSteps(final StringSubstitutor substitutor, final String expectedResult, final String replaceTemplate, final boolean substring, final int targetIndex, final int targetSize) throws IOException { final StringWriter actualResultWriter = new StringWriter(); final StringWriter expectedResultWriter = new StringWriter(); final AtomicInteger index = new AtomicInteger(); final int expectedResultLen = StringUtils.length(expectedResult); try (Reader expectedResultReader = toReader(expectedResult); Reader actualReader = new StringSubstitutorReader(toReader(replaceTemplate), substitutor)) { final char[] actualCh = new char[targetSize]; final char[] expectedCh = new char[targetSize]; int actualCount; while ((actualCount = actualReader.read(actualCh, targetIndex, targetSize - targetIndex)) != -1) { final int expectedCount = expectedResultReader.read(expectedCh, targetIndex, targetSize - targetIndex); if (expectedCount != -1) { expectedResultWriter.write(expectedCh, targetIndex, expectedCount); } // stream can chunk in smaller sizes if (expectedCount == actualCount) { assertEquals(expectedCount, actualCount, () -> String.format("Step size %,d", targetSize)); assertArrayEquals(expectedCh, actualCh, () -> String.format("[%,d] '%s' != '%s', result so far: \"%s\"", index.get(), String.valueOf(expectedCh), String.valueOf(actualCh), actualResultWriter.toString())); } else if (actualCount < expectedCount) { assertTrue(expectedResultWriter.toString().startsWith(actualResultWriter.toString())); } if (actualCount != -1) { actualResultWriter.write(actualCh, targetIndex, actualCount); } else { // fails assertEquals(expectedCount, actualCount, () -> String.format("Step size %,d", targetSize)); } index.incrementAndGet(); assertFalse(index.get() > expectedResultLen, () -> "Index: " + index.get()); // simpler to debug if we zero out the buffers. Arrays.fill(actualCh, (char) 0); Arrays.fill(expectedCh, (char) 0); } } assertEquals(Objects.toString(expectedResult, StringUtils.EMPTY), actualResultWriter.toString()); } private void doTestReplaceInCharArraySteps(final StringSubstitutor substitutor, final String expectedResult, final String replaceTemplate, final boolean substring, final int targetSize) throws IOException { final StringWriter actualResultWriter = new StringWriter(); final StringWriter expectedResultWriter = new StringWriter(); final AtomicInteger index = new AtomicInteger(); final int expectedResultLen = StringUtils.length(expectedResult); try (Reader expectedResultReader = toReader(expectedResult); Reader actualReader = new StringSubstitutorReader(toReader(replaceTemplate), substitutor)) { final char[] actualCh = new char[targetSize]; final char[] expectedCh = new char[targetSize]; int actualCount; while ((actualCount = actualReader.read(actualCh)) != -1) { final int expectedCount = expectedResultReader.read(expectedCh); if (expectedCount != -1) { expectedResultWriter.write(expectedCh, 0, expectedCount); } // stream can chunk in smaller sizes if (expectedCount == actualCount) { assertEquals(expectedCount, actualCount, () -> String.format("Step size %,d", targetSize)); assertArrayEquals(expectedCh, actualCh, () -> String.format("[%,d] '%s' != '%s', result so far: \"%s\"", index.get(), String.valueOf(expectedCh), String.valueOf(actualCh), actualResultWriter.toString())); } else if (actualCount < expectedCount) { assertTrue(expectedResultWriter.toString().startsWith(actualResultWriter.toString())); } if (actualCount != -1) { actualResultWriter.write(actualCh, 0, actualCount); } else { // fails assertEquals(expectedCount, actualCount, () -> String.format("Step size %,d", targetSize)); } index.incrementAndGet(); assertFalse(index.get() > expectedResultLen, () -> "Index: " + index.get()); // simpler to debug if we zero out the buffers. Arrays.fill(actualCh, (char) 0); Arrays.fill(expectedCh, (char) 0); } } assertEquals(Objects.toString(expectedResult, StringUtils.EMPTY), actualResultWriter.toString()); } private void doTestReplaceInCharSteps(final StringSubstitutor substitutor, final String expectedResult, final String replaceTemplate, final boolean substring) throws IOException { final StringWriter actualResultWriter = new StringWriter(); final AtomicInteger index = new AtomicInteger(); final int expectedResultLen = StringUtils.length(expectedResult); try (Reader expectedResultReader = toReader(expectedResult); Reader actualReader = new StringSubstitutorReader(toReader(replaceTemplate), substitutor)) { int actualCh; while ((actualCh = actualReader.read()) != -1) { final int expectedCh = expectedResultReader.read(); final int actualCh2 = actualCh; assertEquals(expectedCh, actualCh, () -> String.format("[%,d] '%s' != '%s', result so far: \"%s\"", index.get(), toStringChar(expectedCh), toStringChar(actualCh2), actualResultWriter.toString())); if (actualCh != -1) { actualResultWriter.write(actualCh); } index.incrementAndGet(); assertFalse(index.get() > expectedResultLen, () -> "Index: " + index.get()); } } assertEquals(Objects.toString(expectedResult, StringUtils.EMPTY), actualResultWriter.toString()); } private int getMinExpressionLength(final StringSubstitutor substitutor) { return substitutor.getVariablePrefixMatcher().size() + 1 + substitutor.getVariableSuffixMatcher().size(); } @Override protected String replace(final StringSubstitutor substitutor, final String source) throws IOException { if (source == null) { return null; } try (Reader reader = createReader(substitutor, source)) { return IOUtils.toString(reader); } } @Test void testReadMixedBufferLengths1ToVarLenPlusNoReplace() throws IOException { final StringSubstitutor substitutor = new StringSubstitutor(values); final String template = "123456"; assertTrue(template.length() > getMinExpressionLength(substitutor) + 1); try (Reader reader = createReader(substitutor, template)) { assertEquals('1', reader.read()); final char[] cbuf = new char[template.length() - 1]; reader.read(cbuf); final String result = String.valueOf(cbuf); assertEquals(template.substring(1), result); } } @Test void testReadMixedBufferLengthsReplace() throws IOException { final String template = "${aa}${bb}"; final StringSubstitutor substitutor = new StringSubstitutor(values); try (Reader reader = createReader(substitutor, template)) { assertEquals('1', reader.read()); final char[] cbuf = new char[3]; assertEquals(0, reader.read(cbuf, 0, 0)); reader.read(cbuf); final String result = String.valueOf(cbuf); assertEquals("122", result, () -> String.format("length %,d", result.length())); } } @Test void testReadMixedBufferLengthsVarLenPlusToNoReplace() throws IOException { final StringSubstitutor substitutor = new StringSubstitutor(values); final String template = "123456"; assertTrue(template.length() > getMinExpressionLength(substitutor) + 1); try (Reader reader = createReader(substitutor, template)) { final int endIndex = template.length() - 1; final char[] cbuf = new char[endIndex]; reader.read(cbuf); final String result = String.valueOf(cbuf); assertEquals(template.substring(0, endIndex), result); assertEquals('6', reader.read()); } } private Reader toReader(final String expectedResult) { return expectedResult != null ? new StringReader(expectedResult) : new NullReader(); } private String toStringChar(final int ch) { switch (ch) { case -1: return "EOS"; case 0: return "NUL"; default: return String.valueOf((char) ch); } } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/jmh/000077500000000000000000000000001511432740600273655ustar00rootroot00000000000000DoubleFormatPerformance.java000066400000000000000000000243411511432740600347220ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/jmh/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.jmh; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.concurrent.TimeUnit; import java.util.function.DoubleFunction; import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.simple.RandomSource; import org.apache.commons.text.numbers.DoubleFormat; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; /** Benchmarks for the {@link DoubleFormat} class. */ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"}) public class DoubleFormatPerformance { /** Benchmark input providing a source of random double values. */ @State(Scope.Thread) public static class DoubleInput { /** The number of doubles in the input array. */ @Param({"10000"}) private int size; /** Minimum base 2 exponent for random input doubles. */ @Param("-100") private int minExp; /** Maximum base 2 exponent for random input doubles. */ @Param("100") private int maxExp; /** Double input array. */ private double[] input; /** Gets the input doubles. * @return the input doubles */ public double[] getInput() { return input; } /** Sets up the instance for the benchmark. */ @Setup(Level.Iteration) public void setup() { input = randomDoubleArray(size, minExp, maxExp, RandomSource.XO_RO_SHI_RO_128_PP.create()); } } /** Decimal format pattern for plain output. */ private static final String PLAIN_PATTERN = "0.0##"; /** Decimal format pattern for plain output with thousands grouping. */ private static final String PLAIN_GROUPED_PATTERN = "#,##0.0##"; /** Decimal format pattern for scientific output. */ private static final String SCI_PATTERN = "0.0##E0"; /** Decimal format pattern for engineering output. */ private static final String ENG_PATTERN = "##0.0##E0"; /** Create a random double value with exponent in the range {@code [minExp, maxExp]}. * @param minExp minimum exponent; must be less than {@code maxExp} * @param maxExp maximum exponent; must be greater than {@code minExp} * @param rng random number generator * @return random double */ private static double randomDouble(final int minExp, final int maxExp, final UniformRandomProvider rng) { // Create random doubles using random bits in the sign bit and the mantissa. final long mask = (1L << 52) - 1 | 1L << 63; final long bits = rng.nextLong() & mask; // The exponent must be unsigned so + 1023 to the signed exponent final long exp = rng.nextInt(maxExp - minExp + 1) + minExp + 1023; return Double.longBitsToDouble(bits | exp << 52); } /** Create an array with the given length containing random doubles with exponents in the range * {@code [minExp, maxExp]}. * @param len array length * @param minExp minimum exponent; must be less than {@code maxExp} * @param maxExp maximum exponent; must be greater than {@code minExp} * @param rng random number generator * @return array of random doubles */ private static double[] randomDoubleArray(final int len, final int minExp, final int maxExp, final UniformRandomProvider rng) { final double[] arr = new double[len]; for (int i = 0; i < arr.length; ++i) { arr[i] = randomDouble(minExp, maxExp, rng); } return arr; } /** Run a benchmark test on a function accepting a double argument. * @param function output type * @param input double array * @param bh jmh blackhole for consuming output * @param fn function to call */ private static void runDoubleFunction(final DoubleInput input, final Blackhole bh, final DoubleFunction fn) { for (final double d : input.getInput()) { bh.consume(fn.apply(d)); } } /** Benchmark testing just the overhead of the benchmark harness. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void baseline(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, d -> "0.0"); } /** Benchmark testing the BigDecimal formatting performance. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void bigDecimal(final DoubleInput input, final Blackhole bh) { final DoubleFunction fn = d -> BigDecimal.valueOf(d) .setScale(3, RoundingMode.HALF_EVEN) .stripTrailingZeros() .toString(); runDoubleFunction(input, bh, fn); } /** Benchmark testing the {@link DecimalFormat} class with engineering format. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void decimalFormatEngineering(final DoubleInput input, final Blackhole bh) { final DecimalFormat fmt = new DecimalFormat(ENG_PATTERN); runDoubleFunction(input, bh, fmt::format); } /** Benchmark testing the {@link DecimalFormat} class. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void decimalFormatPlain(final DoubleInput input, final Blackhole bh) { final DecimalFormat fmt = new DecimalFormat(PLAIN_PATTERN); runDoubleFunction(input, bh, fmt::format); } /** Benchmark testing the {@link DecimalFormat} class with thousands grouping. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void decimalFormatPlainGrouped(final DoubleInput input, final Blackhole bh) { final DecimalFormat fmt = new DecimalFormat(PLAIN_GROUPED_PATTERN); runDoubleFunction(input, bh, fmt::format); } /** Benchmark testing the {@link DecimalFormat} class with scientific format. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void decimalFormatScientific(final DoubleInput input, final Blackhole bh) { final DecimalFormat fmt = new DecimalFormat(SCI_PATTERN); runDoubleFunction(input, bh, fmt::format); } /** Benchmark testing the {@link DoubleFormat#ENGINEERING} format. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void doubleFormatEngineering(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, DoubleFormat.ENGINEERING.builder() .maxPrecision(6) .alwaysIncludeExponent(true) .get()); } /** Benchmark testing the {@link DoubleFormat#PLAIN} format. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void doubleFormatPlain(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, DoubleFormat.PLAIN.builder() .minDecimalExponent(-3) .get()); } /** Benchmark testing the {@link DoubleFormat#PLAIN} format with * thousands grouping. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void doubleFormatPlainGrouped(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, DoubleFormat.PLAIN.builder() .minDecimalExponent(-3) .groupThousands(true) .get()); } /** Benchmark testing the {@link DoubleFormat#SCIENTIFIC} format. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void doubleFormatScientific(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, DoubleFormat.SCIENTIFIC.builder() .maxPrecision(4) .alwaysIncludeExponent(true) .get()); } /** Benchmark testing the {@link Double#toString()} method. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void doubleToString(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, Double::toString); } /** Benchmark testing the {@link String#format(String, Object...)} method. * @param input benchmark state input * @param bh jmh blackhole for consuming output */ @Benchmark public void stringFormat(final DoubleInput input, final Blackhole bh) { runDoubleFunction(input, bh, d -> String.format("%f", d)); } } LongestCommonSubsequencePerformance.java000066400000000000000000000160411511432740600373240ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/jmh/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.jmh; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.text.similarity.LongestCommonSubsequence; import org.apache.commons.text.similarity.SimilarityScore; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; /** * Performance analysis for LongestCommonSubsequence */ @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 5, time = 1) @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"}) public class LongestCommonSubsequencePerformance { /** * Older implementation of LongestCommonSubsequence. * Code is copied from Apache Commons Text version 1.10.0-SNAPSHOT */ private static final class BaselineLongestCommonSubsequence implements SimilarityScore { @Override public Integer apply(final CharSequence left, final CharSequence right) { if (left == null || right == null) { throw new IllegalArgumentException("Inputs must not be null"); } return longestCommonSubsequence(left, right).length(); } public CharSequence longestCommonSubsequence(final CharSequence left, final CharSequence right) { if (left == null || right == null) { throw new IllegalArgumentException("Inputs must not be null"); } final StringBuilder longestCommonSubstringArray = new StringBuilder(Math.max(left.length(), right.length())); final int[][] lcsLengthArray = longestCommonSubstringLengthArray(left, right); int i = left.length() - 1; int j = right.length() - 1; int k = lcsLengthArray[left.length()][right.length()] - 1; while (k >= 0) { if (left.charAt(i) == right.charAt(j)) { longestCommonSubstringArray.append(left.charAt(i)); i = i - 1; j = j - 1; k = k - 1; } else if (lcsLengthArray[i + 1][j] < lcsLengthArray[i][j + 1]) { i = i - 1; } else { j = j - 1; } } return longestCommonSubstringArray.reverse().toString(); } public int[][] longestCommonSubstringLengthArray(final CharSequence left, final CharSequence right) { final int[][] lcsLengthArray = new int[left.length() + 1][right.length() + 1]; for (int i = 0; i < left.length(); i++) { for (int j = 0; j < right.length(); j++) { if (i == 0) { lcsLengthArray[i][j] = 0; } if (j == 0) { lcsLengthArray[i][j] = 0; } if (left.charAt(i) == right.charAt(j)) { lcsLengthArray[i + 1][j + 1] = lcsLengthArray[i][j] + 1; } else { lcsLengthArray[i + 1][j + 1] = Math.max(lcsLengthArray[i + 1][j], lcsLengthArray[i][j + 1]); } } } return lcsLengthArray; } } @State(Scope.Benchmark) public static class InputData { final List> inputs = new ArrayList<>(); @Setup(Level.Trial) public void setup() { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try (InputStream is = classLoader.getResourceAsStream("org/apache/commons/text/lcs-perf-analysis-inputs.csv"); InputStreamReader isr = new InputStreamReader(Objects.requireNonNull(is)); BufferedReader br = new BufferedReader(isr)) { String line; while ((line = br.readLine()) != null && !line.trim().isEmpty()) { line = line.trim(); final int indexOfComma = line.indexOf(','); final String inputA = line.substring(0, indexOfComma); final String inputB = line.substring(1 + indexOfComma); this.inputs.add(ImmutablePair.of(inputA, inputB)); } } catch (final IOException exception) { throw new UncheckedIOException(exception.getMessage(), exception); } } } @Benchmark void testLCS(final InputData data) { final LongestCommonSubsequence lcs = new LongestCommonSubsequence(); for (final Pair input : data.inputs) { lcs.longestCommonSubsequence(input.getLeft(), input.getRight()); } } @Benchmark void testLCSBaseline(final InputData data) { final BaselineLongestCommonSubsequence lcs = new BaselineLongestCommonSubsequence(); for (final Pair input : data.inputs) { lcs.longestCommonSubsequence(input.getLeft(), input.getRight()); } } @Benchmark void testLCSLen(final InputData data) { final LongestCommonSubsequence lcs = new LongestCommonSubsequence(); for (final Pair input : data.inputs) { lcs.apply(input.getLeft(), input.getRight()); } } @Benchmark void testLCSLenBaseline(final InputData data) { final BaselineLongestCommonSubsequence lcs = new BaselineLongestCommonSubsequence(); for (final Pair input : data.inputs) { lcs.apply(input.getLeft(), input.getRight()); } } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/000077500000000000000000000000001511432740600301205ustar00rootroot00000000000000AbstractStringLookupTest.java000066400000000000000000000036461511432740600357010ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; /** * Tests forwarding methods provided by {@link AbstractStringLookup}. */ class AbstractStringLookupTest { private static final class TestStringLookup extends AbstractStringLookup { @Override public String lookup(final String key) { // noop return null; } } @SuppressWarnings("deprecation") @Test void testForwarding_substringAfter() { assertEquals(StringUtils.substringAfterLast("abc", 'a'), new TestStringLookup().substringAfterLast("abc", 'a')); } @SuppressWarnings("deprecation") @Test void testForwarding_substringAfterChar() { assertEquals(StringUtils.substringAfter("abc", 'a'), new TestStringLookup().substringAfter("abc", 'a')); } @SuppressWarnings("deprecation") @Test void testForwarding_substringAfterString() { assertEquals(StringUtils.substringAfter("abc", "a"), new TestStringLookup().substringAfter("abc", "a")); } } Base64DecoderStringLookupTest.java000066400000000000000000000027511511432740600364440ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link StringLookupFactory#INSTANCE_BASE64_DECODER}. */ class Base64DecoderStringLookupTest { @Test void test() { Assertions.assertEquals("HelloWorld!", StringLookupFactory.INSTANCE_BASE64_DECODER.apply("SGVsbG9Xb3JsZCE=")); } @Test void testNull() { Assertions.assertNull(StringLookupFactory.INSTANCE_BASE64_DECODER.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(StringLookupFactory.INSTANCE_BASE64_DECODER.toString().isEmpty()); } } Base64EncoderStringLookupTest.java000066400000000000000000000027511511432740600364560ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link StringLookupFactory#INSTANCE_BASE64_ENCODER}. */ class Base64EncoderStringLookupTest { @Test void test() { Assertions.assertEquals("SGVsbG9Xb3JsZCE=", StringLookupFactory.INSTANCE_BASE64_ENCODER.apply("HelloWorld!")); } @Test void testNull() { Assertions.assertNull(StringLookupFactory.INSTANCE_BASE64_ENCODER.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(StringLookupFactory.INSTANCE_BASE64_ENCODER.toString().isEmpty()); } } BiFunctionStringLookupTest.java000066400000000000000000000077601511432740600361770ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link FunctionStringLookup}. */ class BiFunctionStringLookupTest { private static final String SEPARATOR = "."; @SuppressWarnings("unchecked") private final BiFunction, Object> nestedMapBiFunction = (k, m) -> { final String keyCandidate = StringUtils.substringBefore(k, SEPARATOR); if (keyCandidate.isEmpty()) { return m.get(k); } final Object value = m.get(keyCandidate); if (value instanceof Map) { return this.nestedMapBiFunction.apply(StringUtils.substringAfter(k, SEPARATOR), (Map) value); } return value; }; @Test void testBiFunctionForNestedMap() { // Build map final String subSubKey = "subsubkeyMap"; final String subSubValue = "subsubvalue"; final Map subSubMap = new HashMap<>(); subSubMap.put(subSubKey, subSubValue); // final String subKey = "subkey"; final String subKeyMap = "subkeyMap"; final String subValue = "subvalue"; final Map rootSubMap = new HashMap<>(); rootSubMap.put(subKey, subValue); rootSubMap.put(subKeyMap, subSubMap); // final String rootKey = "keyMap"; final String rootKey2 = "key2"; final String rootValue2 = "value2"; final Map rootMap = new HashMap<>(); rootMap.put(rootKey, rootSubMap); rootMap.put(rootKey2, rootValue2); // Use map final BiStringLookup> stringLookup = StringLookupFactory.INSTANCE .biFunctionStringLookup(nestedMapBiFunction); Assertions.assertEquals(rootValue2, stringLookup.lookup(rootKey2, rootMap)); Assertions.assertEquals(subValue, stringLookup.lookup(rootKey + SEPARATOR + subKey, rootMap)); Assertions.assertEquals(subSubValue, stringLookup.lookup(rootKey + SEPARATOR + subKeyMap + SEPARATOR + subSubKey, rootMap)); } @Test void testConcurrentHashMapNull() { Assertions.assertNull(BiFunctionStringLookup.on(new ConcurrentHashMap<>()).apply(null)); } @Test void testHashMapNull() { Assertions.assertNull(BiFunctionStringLookup.on(new HashMap<>()).apply(null)); } @Test void testNullBiFunction() { Assertions.assertNull(BiFunctionStringLookup.on((BiFunction) null).apply(null)); } @Test void testOne() { final String key = "key"; final String value = "value"; final Map map = new HashMap<>(); map.put(key, value); Assertions.assertEquals(value, FunctionStringLookup.on(map).apply(key)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(BiFunctionStringLookup.on(new HashMap<>()).toString().isEmpty()); } } BiStringLookupTest.java000066400000000000000000000021561511432740600344630ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link BiStringLookup}. */ class BiStringLookupTest { @Test void testDefaultMethod() { Assertions.assertEquals("a", ((BiStringLookup) key -> key).lookup("a", "b")); } } ConstantStringLookupBasicTest.java000066400000000000000000000053371511432740600366700ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests {@link ConstantStringLookup}. */ class ConstantStringLookupBasicTest { /** * Test fixture. */ public static final String NULL_STRING_FIXTURE = null; /** * Test fixture. */ public static final String STRING_FIXTURE = "Hello World!"; /** * Clears the test environment. Here the static cache of the constant lookup class is wiped out. */ @AfterEach public void afterEach() { ConstantStringLookup.clear(); } /** * Clears the test environment. Here the static cache of the constant lookup class is wiped out. */ @BeforeEach public void beforeEach() { ConstantStringLookup.clear(); } @Test void testNull() { Assertions.assertNull(ConstantStringLookup.INSTANCE.apply(null)); } @Test void testNullClassFetch() { Assertions.assertNull(new ConstantStringLookup() { @Override protected Class fetchClass(final String className) throws ClassNotFoundException { return null; } }.apply(ConstantStringLookupBasicTest.class.getName() + ".STRING_FIXTURE")); } @Test void testNullValue() { Assertions.assertEquals(NULL_STRING_FIXTURE, ConstantStringLookup.INSTANCE .apply(ConstantStringLookupBasicTest.class.getName() + ".NULL_STRING_FIXTURE")); } @Test void testOne() { Assertions.assertEquals(STRING_FIXTURE, ConstantStringLookup.INSTANCE.apply(ConstantStringLookupBasicTest.class.getName() + ".STRING_FIXTURE")); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(ConstantStringLookup.INSTANCE.toString().isEmpty()); } } ConstantStringLookupTest.java000066400000000000000000000110201511432740600357100ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.lookup; import java.awt.event.KeyEvent; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Tests {@link ConstantStringLookup}. *

* This class was adapted from Apache Commons Configuration. *

*/ class ConstantStringLookupTest { /** A public field that can be read by the lookup. */ public static final String FIELD = "Field that can be read"; /** A private field that cannot be read by the lookup. */ @SuppressWarnings("unused") private static final String PRIVATE_FIELD = "PRIVATE"; /** The lookup object to be tested. */ private ConstantStringLookup stringLookup; /** * Clears the test environment. Here the static cache of the constant lookup class is wiped out. */ @AfterEach public void afterEach() { ConstantStringLookup.clear(); } /** * Clears the test environment. Here the static cache of the constant lookup class is wiped out. */ @BeforeEach public void beforeEach() { stringLookup = ConstantStringLookup.INSTANCE; } /** * Tests accessing the cache by querying a variable twice. */ @Test void testLookupCache() { testLookupConstant(); testLookupConstant(); } /** * Tests resolving a valid constant. */ @Test void testLookupConstant() { Assertions.assertEquals(FIELD, stringLookup.apply(variable("FIELD")), "Wrong value of constant"); } /** * Tries to resolve a variable with an invalid syntax: The name does not contain a dot as a field separator. */ @Test void testLookupInvalidSyntax() { Assertions.assertNull(stringLookup.apply("InvalidVariableName"), "Non null return value for invalid variable name"); } /** * Tests resolving a non existing constant. Result should be null. */ @Test void testLookupNonExisting() { Assertions.assertNull(stringLookup.apply(variable("NO_FIELD")), "Non null return value for non existing constant"); } /** * Tests resolving a non string constant. Then looks the same variable up from the cache. */ @Test void testLookupNonString() { final String ref = KeyEvent.class.getName() + ".VK_ESCAPE"; final String expected = Integer.toString(KeyEvent.VK_ESCAPE); Assertions.assertEquals(expected, stringLookup.apply(ref), "Wrong result of first lookup"); Assertions.assertEquals(expected, stringLookup.apply(ref), "Wrong result of 2nd lookup"); } /** * Tests looking up a null variable. */ @Test void testLookupNull() { Assertions.assertNull(stringLookup.apply(null), "Non null return value for null variable"); } /** * Tests resolving a private constant. Because a private field cannot be accessed this should again yield null. */ @Test void testLookupPrivate() { Assertions.assertNull(stringLookup.apply(variable("PRIVATE_FIELD")), "Non null return value for non accessible field"); } /** * Tests resolving a field from an unknown class. */ @Test void testLookupUnknownClass() { Assertions.assertNull(stringLookup.apply("org.apache.commons.configuration.NonExistingConfig." + FIELD), "Non null return value for unknown class"); } /** * Generates the name of a variable for a lookup operation based on the given field name of this class. * * @param field the field name * @return the variable for looking up this field */ private String variable(final String field) { return getClass().getName() + '.' + field; } } DateStringLookupTest.java000066400000000000000000000043741511432740600350120ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link DateStringLookup}. */ class DateStringLookupTest { @Test void testBadFormat() { assertThrows(IllegalArgumentException.class, () -> DateStringLookup.INSTANCE.apply("this-is-a-bad-format-dontcha-know")); } @Test void testDefault() throws ParseException { final String formatted = DateStringLookup.INSTANCE.apply(null); DateFormat.getInstance().parse(formatted); // throws ParseException } @Test void testFormat() { final String format = "yyyy-MM-dd"; final String value = DateStringLookup.INSTANCE.apply(format); // System.out.println(value); assertNotNull(value, "No Date"); final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); final String today = simpleDateFormat.format(new Date()); assertEquals(value, today); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(DateStringLookup.INSTANCE.toString().isEmpty()); } } DefaultStringLookupTest.java000066400000000000000000000072511511432740600355160ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertSame; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; /** * Tests {@link DefaultStringLookup}. */ class DefaultStringLookupTest { @Test void testEnumValues() { final Map stringLookupMap = new HashMap<>(); StringLookupFactory.INSTANCE.addDefaultStringLookups(stringLookupMap); // Loop through all enums for (final DefaultStringLookup stringLookup : DefaultStringLookup.values()) { assertSame(stringLookupMap.get(stringLookup.getKey()), stringLookupMap.get(stringLookup.getKey())); } } @Test void testIndividualEnums() { assertSame(DefaultStringLookup.BASE64_DECODER.getStringLookup(), StringLookupFactory.INSTANCE.base64DecoderStringLookup()); assertSame(DefaultStringLookup.BASE64_ENCODER.getStringLookup(), StringLookupFactory.INSTANCE.base64EncoderStringLookup()); assertSame(DefaultStringLookup.CONST.getStringLookup(), StringLookupFactory.INSTANCE.constantStringLookup()); assertSame(DefaultStringLookup.DATE.getStringLookup(), StringLookupFactory.INSTANCE.dateStringLookup()); assertSame(DefaultStringLookup.DNS.getStringLookup(), StringLookupFactory.INSTANCE.dnsStringLookup()); assertSame(DefaultStringLookup.ENVIRONMENT.getStringLookup(), StringLookupFactory.INSTANCE.environmentVariableStringLookup()); assertSame(DefaultStringLookup.FILE.getStringLookup(), StringLookupFactory.INSTANCE.fileStringLookup()); assertSame(DefaultStringLookup.JAVA.getStringLookup(), StringLookupFactory.INSTANCE.javaPlatformStringLookup()); assertSame(DefaultStringLookup.LOCAL_HOST.getStringLookup(), StringLookupFactory.INSTANCE.localHostStringLookup()); assertSame(DefaultStringLookup.PROPERTIES.getStringLookup(), StringLookupFactory.INSTANCE.propertiesStringLookup()); assertSame(DefaultStringLookup.RESOURCE_BUNDLE.getStringLookup(), StringLookupFactory.INSTANCE.resourceBundleStringLookup()); assertSame(DefaultStringLookup.SCRIPT.getStringLookup(), StringLookupFactory.INSTANCE.scriptStringLookup()); assertSame(DefaultStringLookup.SYSTEM_PROPERTIES.getStringLookup(), StringLookupFactory.INSTANCE.systemPropertyStringLookup()); assertSame(DefaultStringLookup.URL.getStringLookup(), StringLookupFactory.INSTANCE.urlStringLookup()); assertSame(DefaultStringLookup.URL_DECODER.getStringLookup(), StringLookupFactory.INSTANCE.urlDecoderStringLookup()); assertSame(DefaultStringLookup.URL_ENCODER.getStringLookup(), StringLookupFactory.INSTANCE.urlEncoderStringLookup()); assertSame(DefaultStringLookup.XML.getStringLookup(), StringLookupFactory.INSTANCE.xmlStringLookup()); } } DnsStringLookupTest.java000066400000000000000000000060101511432740600346460ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import java.net.InetAddress; import java.net.UnknownHostException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link DnsStringLookup}. */ class DnsStringLookupTest { @Test void testAddressFromHostAddress() throws UnknownHostException { final InetAddress localHost = InetAddress.getLocalHost(); Assertions.assertEquals(localHost.getHostAddress(), DnsStringLookup.INSTANCE.apply("address|" + localHost.getHostAddress())); } @Test void testAddressFromHostName() throws UnknownHostException { final InetAddress localHost = InetAddress.getLocalHost(); Assertions.assertEquals(localHost.getHostAddress(), DnsStringLookup.INSTANCE.apply("address|" + localHost.getHostName())); } @Test void testCanonicalNameFromHostAddress() throws UnknownHostException { final InetAddress localHost = InetAddress.getLocalHost(); Assertions.assertEquals(localHost.getCanonicalHostName(), DnsStringLookup.INSTANCE.apply("canonical-name|" + localHost.getHostAddress())); } @Test void testCanonicalNameFromHostName() throws UnknownHostException { final InetAddress localHost = InetAddress.getLocalHost(); Assertions.assertEquals(localHost.getCanonicalHostName(), DnsStringLookup.INSTANCE.apply("canonical-name|" + localHost.getHostName())); } @Test void testName() throws UnknownHostException { final String address = InetAddress.getLocalHost().getHostAddress(); final InetAddress[] localHostAll = InetAddress.getAllByName(address); boolean matched = false; for (final InetAddress localHost : localHostAll) { if (localHost.getHostName().equals(DnsStringLookup.INSTANCE.apply("name|" + address + ""))) { matched = true; } } Assertions.assertTrue(matched); } @Test void testNull() { Assertions.assertNull(DnsStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(DnsStringLookup.INSTANCE.toString().isEmpty()); } } EnvironmentVariableStringLookupTest.java000066400000000000000000000035341511432740600401040ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.apache.commons.lang3.SystemUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link StringLookupFactory#INSTANCE_ENVIRONMENT_VARIABLES}. */ class EnvironmentVariableStringLookupTest { @Test void testNull() { Assertions.assertNull(StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES.apply(null)); } @Test void testOne() { if (SystemUtils.IS_OS_WINDOWS) { final String key = "PATH"; Assertions.assertEquals(System.getenv(key), StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES.apply(key)); } else if (SystemUtils.IS_OS_LINUX) { final String key = "USER"; Assertions.assertEquals(System.getenv(key), StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES.apply(key)); } } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES.toString().isEmpty()); } } FileStringLookupTest.java000066400000000000000000000151541511432740600350120ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringSubstitutor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link FileStringLookup}. */ public class FileStringLookupTest { private static final Path DOCUEMENT_PATH = Paths.get("src/test/resources/org/apache/commons/text/document.properties"); private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); public static String readDocumentFixtureString() throws IOException { return new String(Files.readAllBytes(DOCUEMENT_PATH), StandardCharsets.UTF_8); } public static void testFence(final String expectedString, final FileStringLookup fileStringLookup) { Assertions.assertEquals(expectedString, fileStringLookup.apply("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.apply("UTF-8:/src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.apply("UTF-8:../src/test/resources/org/apache/commons/text/document.properties")); } public static void testFence(final StringSubstitutor stringSubstitutor) throws IOException { assertEquals(readDocumentFixtureString(), stringSubstitutor.replace("${file:UTF-8:" + DOCUEMENT_PATH + "}")); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${file:UTF-8:/foo.txt}")); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${file:UTF-8:../foo.txt}")); } @Test void testDefaultInstanceBadCharsetName() { assertThrows(IllegalArgumentException.class, () -> FileStringLookup.INSTANCE.apply("BAD_CHARSET_NAME:src/test/resources/org/apache/commons/text/document.properties")); } @Test void testDefaultInstanceBadDocumentPath() { assertThrows(IllegalArgumentException.class, () -> FileStringLookup.INSTANCE.apply("BAD_CHARSET_NAME:src/test/resources/DOCUMENT_NOT_FOUND.TXT")); } @Test void testDefaultInstanceMissingFilePart() { assertThrows(IllegalArgumentException.class, () -> FileStringLookup.INSTANCE.apply(StandardCharsets.UTF_8.name())); } @Test void testDefaultInstanceNull() { Assertions.assertNull(FileStringLookup.INSTANCE.apply(null)); } @Test void testDefaultInstanceOne() throws Exception { final String expectedString = readDocumentFixtureString(); Assertions.assertEquals(expectedString, FileStringLookup.INSTANCE.apply("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); } @Test void testDefaultInstanceToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(FileStringLookup.INSTANCE.toString().isEmpty()); } @Test void testFenceBadDirOne() throws Exception { final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("dir does not exist at all")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.apply("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.apply("UTF-8:/src/test/resources/org/apache/commons/text/document.properties")); assertThrows(IllegalArgumentException.class, () -> fileStringLookup.apply("UTF-8:../src/test/resources/org/apache/commons/text/document.properties")); } @Test void testFenceBadDirPlusGoodOne() throws Exception { final String expectedString = readDocumentFixtureString(); final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("dir does not exist at all"), CURRENT_PATH); testFence(expectedString, fileStringLookup); } @Test void testFenceCurrentDirOne() throws Exception { final String expectedString = readDocumentFixtureString(); final FileStringLookup fileStringLookup = new FileStringLookup(CURRENT_PATH); testFence(expectedString, fileStringLookup); } @Test void testFenceCurrentDirPlusOne() throws Exception { final String expectedString = readDocumentFixtureString(); final FileStringLookup fileStringLookup = new FileStringLookup(Paths.get("target"), CURRENT_PATH); testFence(expectedString, fileStringLookup); } @Test void testFenceEmptyOne() throws Exception { final String expectedString = readDocumentFixtureString(); Assertions.assertEquals(expectedString, new FileStringLookup().apply("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); } @Test void testFenceNullOne() throws Exception { final String expectedString = readDocumentFixtureString(); Assertions.assertEquals(expectedString, new FileStringLookup((Path[]) null).apply("UTF-8:src/test/resources/org/apache/commons/text/document.properties")); } @Test void testInterpolatorReplace() throws IOException { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertEquals(readDocumentFixtureString(), stringSubstitutor.replace("${file:UTF-8:" + DOCUEMENT_PATH + "}")); final InterpolatorStringLookup stringLookup = (InterpolatorStringLookup) stringSubstitutor.getStringLookup(); stringLookup.getStringLookupMap().replace(StringLookupFactory.KEY_FILE, StringLookupFactory.INSTANCE.fileStringLookup(CURRENT_PATH)); testFence(stringSubstitutor); } } FunctionStringLookupTest.java000066400000000000000000000037701511432740600357210ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link FunctionStringLookup}. */ class FunctionStringLookupTest { @Test void testConcurrentHashMapNull() { Assertions.assertNull(FunctionStringLookup.on(new ConcurrentHashMap<>()).apply(null)); } @Test void testHashMapNull() { Assertions.assertNull(FunctionStringLookup.on(new HashMap<>()).apply(null)); } @Test void testNullFunction() { Assertions.assertNull(FunctionStringLookup.on((Function) null).apply(null)); } @Test void testOne() { final String key = "key"; final String value = "value"; final Map map = new HashMap<>(); map.put(key, value); Assertions.assertEquals(value, FunctionStringLookup.on(map).apply(key)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(FunctionStringLookup.on(new HashMap<>()).toString().isEmpty()); } } InetAddressStringLookupLocalHostTest.java000066400000000000000000000042051511432740600401440ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import java.net.InetAddress; import java.net.UnknownHostException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link InetAddressStringLookup#LOCAL_HOST}. */ class InetAddressStringLookupLocalHostTest { @Test void testAddress() throws UnknownHostException { Assertions.assertEquals(InetAddress.getLocalHost().getHostAddress(), InetAddressStringLookup.LOCAL_HOST.apply("address")); } @Test void testBadKey() { Assertions.assertThrows(IllegalArgumentException.class, () -> InetAddressStringLookup.LOCAL_HOST.apply("FOO")); } @Test void testCanonicalName() throws UnknownHostException { Assertions.assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), InetAddressStringLookup.LOCAL_HOST.apply("canonical-name")); } @Test void testName() throws UnknownHostException { Assertions.assertEquals(InetAddress.getLocalHost().getHostName(), InetAddressStringLookup.LOCAL_HOST.apply("name")); } @Test void testNull() { Assertions.assertNull(InetAddressStringLookup.LOCAL_HOST.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(InetAddressStringLookup.LOCAL_HOST.toString().isEmpty()); } } InetAddressStringLookupLoopbackAddressTest.java000066400000000000000000000041061511432740600413140ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import java.net.InetAddress; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link InetAddressStringLookup#LOOPACK_ADDRESS}. */ class InetAddressStringLookupLoopbackAddressTest { @Test void testAddress() { Assertions.assertEquals(InetAddress.getLoopbackAddress().getHostAddress(), InetAddressStringLookup.LOOPACK_ADDRESS.apply("address")); } @Test void testBadKey() { Assertions.assertThrows(IllegalArgumentException.class, () -> InetAddressStringLookup.LOOPACK_ADDRESS.apply("FOO")); } @Test void testCanonicalName() { Assertions.assertEquals(InetAddress.getLoopbackAddress().getCanonicalHostName(), InetAddressStringLookup.LOOPACK_ADDRESS.apply("canonical-name")); } @Test void testName() { Assertions.assertEquals(InetAddress.getLoopbackAddress().getHostName(), InetAddressStringLookup.LOOPACK_ADDRESS.apply("name")); } @Test void testNull() { Assertions.assertNull(InetAddressStringLookup.LOOPACK_ADDRESS.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(InetAddressStringLookup.LOOPACK_ADDRESS.toString().isEmpty()); } } InterpolatorStringLookupTest.java000066400000000000000000000105571511432740600366170ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; /** * Tests {@link InterpolatorStringLookup}. */ class InterpolatorStringLookupTest { private static final String TESTKEY = "TestKey"; private static final String TESTKEY2 = "TestKey2"; private static final String TESTVAL = "TestValue"; @AfterAll public static void afterAll() { System.clearProperty(TESTKEY); System.clearProperty(TESTKEY2); } @BeforeAll public static void beforeAll() { System.setProperty(TESTKEY, TESTVAL); System.setProperty(TESTKEY2, TESTVAL); } private void assertLookupNotEmpty(final StringLookup lookup, final String key) { final String value = lookup.apply(key); assertNotNull(value); assertFalse(value.isEmpty()); // System.out.println(key + " = " + value); } private void check(final StringLookup lookup) { String value = lookup.apply("sys:" + TESTKEY); assertEquals(TESTVAL, value); value = lookup.apply("env:PATH"); assertNotNull(value); value = lookup.apply("date:yyyy-MM-dd"); assertNotNull(value, "No Date"); final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); final String today = format.format(new Date()); assertEquals(value, today); assertLookupNotEmpty(lookup, "java:version"); assertLookupNotEmpty(lookup, "java:runtime"); assertLookupNotEmpty(lookup, "java:vm"); assertLookupNotEmpty(lookup, "java:os"); assertLookupNotEmpty(lookup, "java:locale"); assertLookupNotEmpty(lookup, "java:hardware"); } @Test void testLookup() { final Map map = new HashMap<>(); map.put(TESTKEY, TESTVAL); final StringLookup lookup = new InterpolatorStringLookup(StringLookupFactory.INSTANCE.mapStringLookup(map)); String value = lookup.apply(TESTKEY); assertEquals(TESTVAL, value); value = lookup.apply("ctx:" + TESTKEY); assertEquals(TESTVAL, value); value = lookup.apply("sys:" + TESTKEY); assertEquals(TESTVAL, value); value = lookup.apply("BadKey"); assertNull(value); value = lookup.apply("ctx:" + TESTKEY); assertEquals(TESTVAL, value); } @Test void testLookupKeys() { final InterpolatorStringLookup lookup = new InterpolatorStringLookup((Map) null); final Map stringLookupMap = lookup.getStringLookupMap(); StringLookupFactoryTest.assertDefaultKeys(stringLookupMap); } @Test void testLookupWithDefaultInterpolator() { check(new InterpolatorStringLookup()); } @Test void testLookupWithNullDefaultInterpolator() { check(new InterpolatorStringLookup((StringLookup) null)); } @Test void testNull() { Assertions.assertNull(InterpolatorStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(new InterpolatorStringLookup().toString().isEmpty()); } } JavaPlatformStringLookupTest.java000066400000000000000000000036061511432740600365200ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.apache.commons.lang3.ArrayUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link JavaPlatformStringLookup}. */ class JavaPlatformStringLookupTest { @Test void testBadKey() { assertThrows(IllegalArgumentException.class, () -> JavaPlatformStringLookup.INSTANCE.apply("BADKEY")); } @Test void testMain() { JavaPlatformStringLookup.main(ArrayUtils.EMPTY_STRING_ARRAY); } @Test void testNull() { Assertions.assertNull(JavaPlatformStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(JavaPlatformStringLookup.INSTANCE.toString().isEmpty()); } @Test void testVm() { final String key = "vm"; assertTrue(JavaPlatformStringLookup.INSTANCE.apply(key).contains(System.getProperty("java.vm.name"))); } } NullStringLookupTest.java000066400000000000000000000026001511432740600350350ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link StringLookupFactory#INSTANCE_NULL}. */ class NullStringLookupTest { @Test void test() { Assertions.assertNull(StringLookupFactory.INSTANCE_NULL.apply("EverythingIsNull")); Assertions.assertNull(StringLookupFactory.INSTANCE_NULL.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(StringLookupFactory.INSTANCE_NULL.toString().isEmpty()); } } PropertiesStringLookupTest.java000066400000000000000000000201741511432740600362650ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringSubstitutor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link PropertiesStringLookup}. */ public class PropertiesStringLookupTest { private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); // NOT "."! private static final String DOC_RELATIVE = "src/test/resources/org/apache/commons/text/document.properties"; private static final String DOC_ROOT = "/foo.txt"; private static final String KEY = "mykey"; private static final String KEY_RELATIVE = PropertiesStringLookup.toPropertyKey(DOC_RELATIVE, KEY); private static final String KEY_ROOT = PropertiesStringLookup.toPropertyKey(DOC_ROOT, KEY); private static final Path[] NULL_PATH_ARRAY = null; public static void testFence(final StringSubstitutor stringSubstitutor) { assertEquals("Hello World!", stringSubstitutor.replace("${properties:" + KEY_RELATIVE + "}")); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${file:UTF-8:/foo.txt}")); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${file:UTF-8:../foo.txt}")); } @Test void testFenceOne() { assertThrows(IllegalArgumentException.class, () -> new PropertiesStringLookup(CURRENT_PATH).apply(KEY_ROOT)); assertThrows(IllegalArgumentException.class, () -> new PropertiesStringLookup(Paths.get("not a dir at all"), CURRENT_PATH).apply(KEY_ROOT)); } @Test void testInterpolator() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertEquals("Hello World!", stringSubstitutor.replace("${properties:" + KEY_RELATIVE + "}")); } @Test void testInterpolatorNestedColon() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); // Need to handle "C:" in the sys prop user.dir. final String replaced = stringSubstitutor.replace("$${properties:${sys:user.dir}/" + KEY_RELATIVE + "}"); assertEquals("${properties:" + System.getProperty("user.dir") + "/src/test/resources/org/apache/commons/text/document.properties::mykey}", replaced); assertEquals("Hello World!", stringSubstitutor.replace(replaced)); } @Test void testInterpolatorReplace() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertEquals("Hello World!", stringSubstitutor.replace("${properties:" + KEY_RELATIVE + "}")); final InterpolatorStringLookup stringLookup = (InterpolatorStringLookup) stringSubstitutor.getStringLookup(); stringLookup.getStringLookupMap().replace(StringLookupFactory.KEY_FILE, StringLookupFactory.INSTANCE.fileStringLookup(CURRENT_PATH)); testFence(stringSubstitutor); } @Test void testInterpolatorReplaceProperties() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertEquals("Hello World!", stringSubstitutor.replace("${properties:" + KEY_RELATIVE + "}")); final InterpolatorStringLookup stringLookup = (InterpolatorStringLookup) stringSubstitutor.getStringLookup(); stringLookup.getStringLookupMap().replace(StringLookupFactory.KEY_PROPERTIES, StringLookupFactory.INSTANCE.propertiesStringLookup(CURRENT_PATH)); assertEquals("Hello World!", stringSubstitutor.replace("${properties:" + KEY_RELATIVE + "}")); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${properties:UTF-8:/foo.txt}")); } @Test void testInterpolatorWithParameterizedKey() { final Map map = new HashMap<>(); map.put("KeyIsHere", KEY); final StringSubstitutor stringSubstitutor = new StringSubstitutor(StringLookupFactory.INSTANCE.interpolatorStringLookup(map)); final String replaced = stringSubstitutor.replace("$${properties:" + PropertiesStringLookup.toPropertyKey(DOC_RELATIVE, "${KeyIsHere}}")); assertEquals("${properties:" + PropertiesStringLookup.toPropertyKey(DOC_RELATIVE, "mykey}"), replaced); assertEquals("Hello World!", stringSubstitutor.replace(replaced)); } @Test void testInterpolatorWithParameterizedKey2() { final Map map = new HashMap<>(); map.put("KeyIsHere", KEY); final StringSubstitutor stringSubstitutor = new StringSubstitutor(StringLookupFactory.INSTANCE.interpolatorStringLookup(map)); final String replaced = stringSubstitutor .replace("$${properties:${sys:user.dir}/" + PropertiesStringLookup.toPropertyKey(DOC_RELATIVE, "${KeyIsHere}}")); assertEquals("${properties:" + System.getProperty("user.dir") + "/" + PropertiesStringLookup.toPropertyKey(DOC_RELATIVE, "mykey}"), replaced); assertEquals("Hello World!", stringSubstitutor.replace(replaced)); } @Test void testMissingFile() { assertThrows(IllegalArgumentException.class, () -> PropertiesStringLookup.INSTANCE.apply("MissingFile")); } @Test void testMissingFileWithKey() { assertThrows(IllegalArgumentException.class, () -> PropertiesStringLookup.INSTANCE.apply(PropertiesStringLookup.toPropertyKey("MissingFile", "AnyKey"))); } @Test void testMissingKey() { assertThrows(IllegalArgumentException.class, () -> PropertiesStringLookup.INSTANCE.apply(DOC_RELATIVE)); assertThrows(IllegalArgumentException.class, () -> new PropertiesStringLookup().apply(DOC_RELATIVE)); assertThrows(IllegalArgumentException.class, () -> new PropertiesStringLookup(NULL_PATH_ARRAY).apply(DOC_RELATIVE)); assertThrows(IllegalArgumentException.class, () -> new PropertiesStringLookup(CURRENT_PATH).apply(DOC_RELATIVE)); } @Test void testNull() { Assertions.assertNull(PropertiesStringLookup.INSTANCE.apply(null)); Assertions.assertNull(new PropertiesStringLookup().apply(null)); Assertions.assertNull(new PropertiesStringLookup(NULL_PATH_ARRAY).apply(null)); Assertions.assertNull(new PropertiesStringLookup(CURRENT_PATH).apply(null)); } @Test void testOne() { assertEquals("Hello World!", PropertiesStringLookup.INSTANCE.apply(KEY_RELATIVE)); assertEquals("Hello World!", new PropertiesStringLookup().apply(KEY_RELATIVE)); assertEquals("Hello World!", new PropertiesStringLookup(NULL_PATH_ARRAY).apply(KEY_RELATIVE)); assertEquals("Hello World!", new PropertiesStringLookup(CURRENT_PATH).apply(KEY_RELATIVE)); assertThrows(IllegalArgumentException.class, () -> new PropertiesStringLookup(CURRENT_PATH).apply(KEY_ROOT)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(PropertiesStringLookup.INSTANCE.toString().isEmpty()); Assertions.assertFalse(new PropertiesStringLookup().toString().isEmpty()); Assertions.assertFalse(new PropertiesStringLookup(NULL_PATH_ARRAY).toString().isEmpty()); Assertions.assertFalse(new PropertiesStringLookup(CURRENT_PATH).toString().isEmpty()); } } ResourceBundleStringLookupTest.java000066400000000000000000000070231511432740600370500ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import java.util.ResourceBundle; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link ResourceBundleStringLookup}. */ class ResourceBundleStringLookupTest { private static final String KEY = "key"; private static final String TEST_RESOURCE_BUNDLE = "org.apache.commons.text.example.testResourceBundleLookup"; @Test void testAny() { final String bundleName = TEST_RESOURCE_BUNDLE; final String bundleKey = KEY; Assertions.assertEquals(ResourceBundle.getBundle(bundleName).getString(bundleKey), ResourceBundleStringLookup.INSTANCE.apply(AbstractStringLookup.toLookupKey(bundleName, bundleKey))); } @Test void testBadKey() { final String bundleName = TEST_RESOURCE_BUNDLE; final String bundleKey = "bad_key"; assertNull(new ResourceBundleStringLookup(bundleName).apply(bundleKey)); assertNull(ResourceBundleStringLookup.INSTANCE.apply(AbstractStringLookup.toLookupKey(bundleName, bundleKey))); } @Test void testBadNames() { assertNull(ResourceBundleStringLookup.INSTANCE .apply(AbstractStringLookup.toLookupKey("BAD_RESOURCE_BUNDLE_NAME", "KEY"))); } @Test void testDoubleBundle() { assertThrows(IllegalArgumentException.class, () -> new ResourceBundleStringLookup(TEST_RESOURCE_BUNDLE) .apply(AbstractStringLookup.toLookupKey("OtherBundle", KEY))); } @Test void testExceptionGettingString() { final ResourceBundleStringLookup mockLookup = spy(ResourceBundleStringLookup.class); when(mockLookup.getString(TEST_RESOURCE_BUNDLE, KEY)).thenThrow(ClassCastException.class); assertThrows(IllegalArgumentException.class, () -> mockLookup.apply(AbstractStringLookup.toLookupKey(TEST_RESOURCE_BUNDLE, KEY))); } @Test void testMissingKeyInSpec() { assertThrows(IllegalArgumentException.class, () -> ResourceBundleStringLookup.INSTANCE.apply(TEST_RESOURCE_BUNDLE + ":")); } @Test void testNull() { Assertions.assertNull(ResourceBundleStringLookup.INSTANCE.apply(null)); } @Test void testOne() { Assertions.assertEquals(ResourceBundle.getBundle(TEST_RESOURCE_BUNDLE).getString(KEY), new ResourceBundleStringLookup(TEST_RESOURCE_BUNDLE).apply(KEY)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(ResourceBundleStringLookup.INSTANCE.toString().isEmpty()); } } ScriptEngineFactoryHelper.java000066400000000000000000000034171511432740600357730ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; /** Helper to see what ScriptEngineFactory are the classpath. */ public class ScriptEngineFactoryHelper { public static void main(final String[] args) { final String indent = " "; for (final ScriptEngineFactory factory : new ScriptEngineManager().getEngineFactories()) { System.out.println(factory); System.out.println(indent + factory.getEngineName()); System.out.println(indent + factory.getEngineVersion()); System.out.println(indent + factory.getLanguageName()); System.out.println(indent + factory.getLanguageVersion()); System.out.println(indent + factory.getClass()); System.out.println(indent + factory.getExtensions()); System.out.println(indent + factory.getMimeTypes()); System.out.println(indent + factory.getNames()); } } } ScriptStringLookupTest.java000066400000000000000000000050731511432740600353760ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertThrows; import javax.script.ScriptEngineManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link ScriptStringLookup}. */ class ScriptStringLookupTest { private static final String JS_NAME = "JavaScript"; @Test void testBadEngineName() { assertThrows(IllegalArgumentException.class, () -> ScriptStringLookup.INSTANCE.apply("BAD_ENGINE_NAME:\"Hello World!\"")); } @Test void testBadScript() { assertThrows(IllegalArgumentException.class, () -> ScriptStringLookup.INSTANCE.apply(JS_NAME + ":X")); } @Test void testNoScript() { assertThrows(IllegalArgumentException.class, () -> ScriptStringLookup.INSTANCE.apply("ENGINE_NAME:")); } @Test void testNull() { Assertions.assertNull(ScriptStringLookup.INSTANCE.apply(null)); } @Test void testOne() { Assertions.assertEquals("Hello World!", ScriptStringLookup.INSTANCE.apply(JS_NAME + ":\"Hello World!\"")); } @Test void testSanityCheck() { Assertions.assertNotNull(new ScriptEngineManager().getEngineByName(JS_NAME), JS_NAME); } @Test void testScriptMissingColon() { assertThrows(IllegalArgumentException.class, () -> ScriptStringLookup.INSTANCE.apply("JavaScript=\"test\"")); } @Test void testScriptUsingMultipleColons() { Assertions.assertEquals("It Works", ScriptStringLookup.INSTANCE.apply(JS_NAME + ":true ? \"It Works\" : \"It Does Not Work\" ")); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(ScriptStringLookup.INSTANCE.toString().isEmpty()); } } StringLookupFactoryTest.java000066400000000000000000000341151511432740600355400ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.xml.XMLConstants; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; /** * Tests {@link StringLookupFactory}. */ class StringLookupFactoryTest { public static void assertDefaultKeys(final Map stringLookupMap) { // included assertMappedLookups(stringLookupMap, "base64", StringLookupFactory.KEY_BASE64_DECODER, StringLookupFactory.KEY_BASE64_ENCODER, StringLookupFactory.KEY_CONST, StringLookupFactory.KEY_DATE, StringLookupFactory.KEY_ENV, StringLookupFactory.KEY_FILE, StringLookupFactory.KEY_JAVA, StringLookupFactory.KEY_LOCALHOST, StringLookupFactory.KEY_LOOPBACK_ADDRESS, StringLookupFactory.KEY_PROPERTIES, StringLookupFactory.KEY_RESOURCE_BUNDLE, StringLookupFactory.KEY_SYS, StringLookupFactory.KEY_URL_DECODER, StringLookupFactory.KEY_URL_ENCODER, StringLookupFactory.KEY_XML, StringLookupFactory.KEY_XML_DECODER, StringLookupFactory.KEY_XML_ENCODER); } private static void assertMappedLookups(final Map lookupMap, final String... keys) { final Set remainingKeys = new HashSet<>(lookupMap.keySet()); for (final String key : keys) { final String normalizedKey = StringLookupFactory.toKey(key); assertNotNull(normalizedKey, () -> "Expected map to contain string lookup for key " + key); remainingKeys.remove(normalizedKey); } assertTrue(remainingKeys.isEmpty(), () -> "Unexpected keys in lookup map: " + remainingKeys); } private static void checkDefaultStringLookupsHolder(final Properties props, final String... keys) { final StringLookupFactory.DefaultStringLookupsHolder holder = new StringLookupFactory.DefaultStringLookupsHolder(props); final Map lookupMap = holder.getDefaultStringLookups(); assertMappedLookups(lookupMap, keys); } /** * Main method used to verify the default string lookups resolved during JVM execution. * @param args */ public static void main(final String[] args) { final Map lookupMap = new HashMap<>(); StringLookupFactory.INSTANCE.addDefaultStringLookups(lookupMap); System.out.println("Default string lookups"); for (final String key : lookupMap.keySet()) { System.out.println("- " + key); } } @Test void testAddDefaultStringLookupsMap() { final Map stringLookupMap = new HashMap<>(); StringLookupFactory.INSTANCE.addDefaultStringLookups(stringLookupMap); assertDefaultKeys(stringLookupMap); } @Test void testAddDefaultStringLookupsNull() { StringLookupFactory.INSTANCE.addDefaultStringLookups(null); } /** * Tests that we return the singleton. */ @Test void testDefault() { final StringLookupFactory stringLookupFactory = StringLookupFactory.INSTANCE; final Map stringLookupMap = new HashMap<>(); stringLookupFactory.addDefaultStringLookups(stringLookupMap); assertTrue(stringLookupMap.containsKey("base64")); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_BASE64_ENCODER.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_CONST.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_DATE)); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_ENV.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_FILE.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_JAVA.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_LOCALHOST.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_LOOPBACK_ADDRESS.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_PROPERTIES.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_RESOURCE_BUNDLE.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_SYS.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_URL_DECODER.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_URL_ENCODER.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_XML.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_XML_DECODER.toLowerCase(Locale.ROOT))); assertTrue(stringLookupMap.containsKey(StringLookupFactory.KEY_XML_ENCODER.toLowerCase(Locale.ROOT))); } @Test void testDefaultStringLookupsHolder_allLookups() { final Properties props = new Properties(); props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "BASE64_DECODER BASE64_ENCODER const, date, dns, environment " + "file ,java, local_host properties, resource_bundle,script,system_properties url url_decoder , url_encoder, xml"); // @formatter:off checkDefaultStringLookupsHolder(props, "base64", StringLookupFactory.KEY_BASE64_DECODER, StringLookupFactory.KEY_BASE64_ENCODER, StringLookupFactory.KEY_CONST, StringLookupFactory.KEY_DATE, StringLookupFactory.KEY_ENV, StringLookupFactory.KEY_FILE, StringLookupFactory.KEY_JAVA, StringLookupFactory.KEY_LOCALHOST, StringLookupFactory.KEY_LOOPBACK_ADDRESS, StringLookupFactory.KEY_PROPERTIES, StringLookupFactory.KEY_RESOURCE_BUNDLE, StringLookupFactory.KEY_SYS, StringLookupFactory.KEY_URL_DECODER, StringLookupFactory.KEY_URL_ENCODER, StringLookupFactory.KEY_XML, StringLookupFactory.KEY_DNS, StringLookupFactory.KEY_URL, StringLookupFactory.KEY_SCRIPT); // @formatter:on } @Test void testDefaultStringLookupsHolder_givenSingleLookup() { final Properties props = new Properties(); props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "base64_encoder"); checkDefaultStringLookupsHolder(props, "base64", StringLookupFactory.KEY_BASE64_ENCODER); } @Test void testDefaultStringLookupsHolder_givenSingleLookup_weirdString() { final Properties props = new Properties(); props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, " \n \t ,, DnS , , "); checkDefaultStringLookupsHolder(props, StringLookupFactory.KEY_DNS); } @Test void testDefaultStringLookupsHolder_invalidLookupsDefinition() { final Properties props = new Properties(); props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "base64_encoder nope"); final Exception exc = assertThrows(IllegalArgumentException.class, () -> new StringLookupFactory.DefaultStringLookupsHolder(props)); assertEquals("Invalid default string lookups definition: base64_encoder nope", exc.getMessage()); } @Test void testDefaultStringLookupsHolder_lookupsPropertyEmptyAndBlank() { final Properties propsWithNull = new Properties(); propsWithNull.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, ""); checkDefaultStringLookupsHolder(propsWithNull); final Properties propsWithBlank = new Properties(); propsWithBlank.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, " "); checkDefaultStringLookupsHolder(propsWithBlank); } @Test void testDefaultStringLookupsHolder_lookupsPropertyNotPresent() { // @formatter:off checkDefaultStringLookupsHolder(new Properties(), "base64", StringLookupFactory.KEY_BASE64_DECODER, StringLookupFactory.KEY_BASE64_ENCODER, StringLookupFactory.KEY_CONST, StringLookupFactory.KEY_DATE, StringLookupFactory.KEY_ENV, StringLookupFactory.KEY_FILE, StringLookupFactory.KEY_JAVA, StringLookupFactory.KEY_LOCALHOST, StringLookupFactory.KEY_LOOPBACK_ADDRESS, StringLookupFactory.KEY_PROPERTIES, StringLookupFactory.KEY_RESOURCE_BUNDLE, StringLookupFactory.KEY_SYS, StringLookupFactory.KEY_URL_DECODER, StringLookupFactory.KEY_URL_ENCODER, StringLookupFactory.KEY_XML, StringLookupFactory.KEY_XML_DECODER, StringLookupFactory.KEY_XML_ENCODER); // @formatter:on } @Test void testDefaultStringLookupsHolder_multipleLookups() { final Properties props = new Properties(); props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "dns, url script "); // @formatter:off checkDefaultStringLookupsHolder(props, StringLookupFactory.KEY_DNS, StringLookupFactory.KEY_URL, StringLookupFactory.KEY_SCRIPT); // @formatter:on } /** * Tests that we return the singleton. */ @Test void testSingletons() { final StringLookupFactory stringLookupFactory = StringLookupFactory.INSTANCE; assertSame(StringLookupFactory.INSTANCE_BASE64_DECODER, stringLookupFactory.base64DecoderStringLookup()); assertSame(StringLookupFactory.INSTANCE_BASE64_ENCODER, stringLookupFactory.base64EncoderStringLookup()); assertSame(ConstantStringLookup.INSTANCE, stringLookupFactory.constantStringLookup()); assertSame(DateStringLookup.INSTANCE, stringLookupFactory.dateStringLookup()); assertSame(DnsStringLookup.INSTANCE, stringLookupFactory.dnsStringLookup()); assertSame(StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES, stringLookupFactory.environmentVariableStringLookup()); assertSame(InterpolatorStringLookup.INSTANCE, stringLookupFactory.interpolatorStringLookup()); assertSame(JavaPlatformStringLookup.INSTANCE, stringLookupFactory.javaPlatformStringLookup()); assertSame(InetAddressStringLookup.LOCAL_HOST, stringLookupFactory.localHostStringLookup()); assertSame(InetAddressStringLookup.LOOPACK_ADDRESS, stringLookupFactory.loopbackAddressStringLookup()); assertSame(StringLookupFactory.INSTANCE_NULL, stringLookupFactory.nullStringLookup()); assertSame(ResourceBundleStringLookup.INSTANCE, stringLookupFactory.resourceBundleStringLookup()); assertSame(ScriptStringLookup.INSTANCE, stringLookupFactory.scriptStringLookup()); assertSame(StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES, stringLookupFactory.systemPropertyStringLookup()); assertSame(UrlDecoderStringLookup.INSTANCE, stringLookupFactory.urlDecoderStringLookup()); assertSame(UrlEncoderStringLookup.INSTANCE, stringLookupFactory.urlEncoderStringLookup()); assertSame(UrlStringLookup.INSTANCE, stringLookupFactory.urlStringLookup()); assertSame(XmlStringLookup.INSTANCE, stringLookupFactory.xmlStringLookup()); assertSame(XmlDecoderStringLookup.INSTANCE, stringLookupFactory.xmlDecoderStringLookup()); assertSame(XmlEncoderStringLookup.INSTANCE, stringLookupFactory.xmlEncoderStringLookup()); } @Test void testXmlStringLookup() { final StringLookupFactory stringLookupFactory = StringLookupFactory.INSTANCE; final HashMap features = new HashMap<>(1); features.put(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); XmlStringLookupTest.assertLookup(stringLookupFactory.xmlStringLookup(features)); XmlStringLookupTest.assertLookup(stringLookupFactory.xmlStringLookup(new HashMap<>())); } @Test void testXmlStringLookupExternalEntityOff() { assertThrows(IllegalArgumentException.class, () -> StringLookupFactory.INSTANCE.xmlStringLookup().apply(XmlStringLookupTest.DOC_DIR + "document-entity-ref.xml:/document/content")); } @Test @SetSystemProperty(key = "XmlStringLookup.secure", value = "false") void testXmlStringLookupExternalEntityOn() { final String key = XmlStringLookupTest.DOC_DIR + "document-entity-ref.xml:/document/content"; assertEquals(XmlStringLookupTest.DATA, StringLookupFactory.INSTANCE.xmlStringLookup(XmlStringLookupTest.EMPTY_MAP).apply(key).trim()); } } SystemPropertyStringLookupTest.java000066400000000000000000000030411511432740600371540ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link StringLookupFactory#INSTANCE_SYSTEM_PROPERTIES}. */ class SystemPropertyStringLookupTest { @Test void testNull() { Assertions.assertNull(StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES.toString().isEmpty()); } @Test void testUserName() { final String key = "user.name"; Assertions.assertEquals(System.getProperty(key), StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES.apply(key)); } } UrlDecoderStringLookupTest.java000066400000000000000000000045541511432740600361650ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link UrlDecoderStringLookup}. */ class UrlDecoderStringLookupTest { private static final String DATA = "Hello World!"; @Test void testAllPercent() { Assertions.assertEquals(DATA, UrlDecoderStringLookup.INSTANCE.apply("Hello%20World%21")); } @Test void testExceptionGettingString() throws UnsupportedEncodingException { final UrlDecoderStringLookup mockLookup = spy(UrlDecoderStringLookup.class); when(mockLookup.decode(DATA, StandardCharsets.UTF_8.displayName())) .thenThrow(UnsupportedEncodingException.class); assertThrows(IllegalArgumentException.class, () -> mockLookup.apply(DATA)); } @Test void testExclamation() { Assertions.assertEquals(DATA, UrlDecoderStringLookup.INSTANCE.apply("Hello%20World!")); } @Test void testNull() { Assertions.assertNull(UrlDecoderStringLookup.INSTANCE.apply(null)); } @Test void testPlus() { Assertions.assertEquals(DATA, UrlDecoderStringLookup.INSTANCE.apply("Hello+World!")); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(UrlDecoderStringLookup.INSTANCE.toString().isEmpty()); } } UrlEncoderStringLookupTest.java000066400000000000000000000041151511432740600361700ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link UrlEncoderStringLookup}. */ class UrlEncoderStringLookupTest { private static final String DATA = "Hello+World%21"; @Test void test() { Assertions.assertEquals(DATA, UrlEncoderStringLookup.INSTANCE.apply("Hello World!")); } @Test void testExceptionGettingString() throws UnsupportedEncodingException { final UrlEncoderStringLookup mockLookup = spy(UrlEncoderStringLookup.class); when(mockLookup.encode(DATA, StandardCharsets.UTF_8.displayName())) .thenThrow(UnsupportedEncodingException.class); assertThrows(IllegalArgumentException.class, () -> mockLookup.apply(DATA)); } @Test void testNull() { Assertions.assertNull(UrlEncoderStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(UrlEncoderStringLookup.INSTANCE.toString().isEmpty()); } } UrlStringLookupTest.java000066400000000000000000000054611511432740600346750ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertThrows; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link UrlStringLookup}. */ class UrlStringLookupTest { @Test void testBadCharsetName() { assertThrows(IllegalArgumentException.class, () -> UrlStringLookup.INSTANCE.apply("BAD_CHARSET_NAME:BAD_URL")); } @Test void testBadEncoding() { assertThrows(IllegalArgumentException.class, () -> UrlStringLookup.INSTANCE.apply("FOO:https://www.google.com")); } @Test void testBadUrl() { assertThrows(IllegalArgumentException.class, () -> UrlStringLookup.INSTANCE.apply("UTF-8:BAD_URL")); } @Test void testFileScheme() throws Exception { final Path path = Paths.get("src/test/resources/org/apache/commons/text/document.properties"); final URI uri = path.toUri(); // System.out.println(uri); final byte[] expectedBytes = Files.readAllBytes(path); final String expectedString = new String(expectedBytes, StandardCharsets.UTF_8); Assertions.assertEquals(expectedString, UrlStringLookup.INSTANCE.apply("UTF-8:" + uri.toString())); } @Test void testHttpScheme() { Assertions.assertNotNull(UrlStringLookup.INSTANCE.apply("UTF-8:https://www.apache.org")); Assertions.assertNotNull(UrlStringLookup.INSTANCE.apply("UTF-8:https://www.google.com")); } @Test void testMissingUrl() { assertThrows(IllegalArgumentException.class, () -> UrlStringLookup.INSTANCE.apply("UTF-8")); } @Test void testNull() { Assertions.assertNull(UrlStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(UrlStringLookup.INSTANCE.toString().isEmpty()); } } XmlDecoderStringLookupTest.java000066400000000000000000000027361511432740600361630ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link XmlDecoderStringLookup}. */ class XmlDecoderStringLookupTest { private static final String DATA = ""; @Test void testDecode() { Assertions.assertEquals(DATA, XmlDecoderStringLookup.INSTANCE.apply("<element>")); } @Test void testNull() { Assertions.assertNull(XmlDecoderStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(XmlDecoderStringLookup.INSTANCE.toString().isEmpty()); } } XmlEncoderStringLookupTest.java000066400000000000000000000027361511432740600361750ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link XmlEncoderStringLookup}. */ class XmlEncoderStringLookupTest { private static final String DATA = "<element>"; @Test void testDecode() { Assertions.assertEquals(DATA, XmlEncoderStringLookup.INSTANCE.apply("")); } @Test void testNull() { Assertions.assertNull(XmlEncoderStringLookup.INSTANCE.apply(null)); } @Test void testToString() { // does not blow up and gives some kind of string. Assertions.assertFalse(XmlEncoderStringLookup.INSTANCE.toString().isEmpty()); } } XmlStringLookupTest.java000066400000000000000000000162741511432740600346770ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.xml.XMLConstants; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringSubstitutor; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; /** * Tests {@link XmlStringLookup}. */ class XmlStringLookupTest { static final String DATA = "Hello World!"; static final Map EMPTY_MAP = Collections.emptyMap(); private static final Path CURRENT_PATH = Paths.get(StringUtils.EMPTY); // NOT "." private static final Path ABSENT_PATH = Paths.get("does not exist at all"); static final String DOC_DIR = "src/test/resources/org/apache/commons/text/"; private static final String DOC_RELATIVE = DOC_DIR + "document.xml"; private static final String DOC_ROOT = "/document.xml"; static void assertLookup(final StringLookup xmlStringLookup) { assertNotNull(xmlStringLookup); assertInstanceOf(XmlStringLookup.class, xmlStringLookup); assertEquals(DATA, xmlStringLookup.apply(DOC_RELATIVE + ":/root/path/to/node")); assertNull(xmlStringLookup.apply(null)); } @Test void testBadXPath() { assertThrows(IllegalArgumentException.class, () -> XmlStringLookup.INSTANCE.apply("docName")); } @Test void testExternalEntityOff() { assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(XmlStringLookup.DEFAULT_XML_FEATURES, EMPTY_MAP).apply(DOC_DIR + "document-entity-ref.xml:/document/content")); } @Test void testExternalEntityOn() { final String key = DOC_DIR + "document-entity-ref.xml:/document/content"; assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP).apply(key).trim()); assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, XmlStringLookup.DEFAULT_XPATH_FEATURES).apply(key).trim()); } @Test void testInterpolatorExternalDtdOff() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-external-dtd.xml:/document/content}")); } @Test @SetSystemProperty(key = "javax.xml.accessExternalDTD", value = "file") void testInterpolatorExternalDtdOn() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertEquals("This is an external entity.", stringSubstitutor.replace("${xml:" + DOC_DIR + "document-external-dtd.xml:/document/content}").trim()); } @Test void testInterpolatorExternalEntityOff() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}")); } @Test @SetSystemProperty(key = "javax.xml.accessExternalDTD", value = "file") void testInterpolatorExternalEntityOffOverride() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertEquals(DATA, stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}").trim()); } @Test void testInterpolatorExternalEntityOn() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}")); } @Test void testInterpolatorExternalEntityOnOverride() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "document-entity-ref.xml:/document/content}")); } @Test void testInterpolatorSecureOnBla() { final StringSubstitutor stringSubstitutor = StringSubstitutor.createInterpolator(); assertThrows(IllegalArgumentException.class, () -> stringSubstitutor.replace("${xml:" + DOC_DIR + "bla.xml:/document/content}")); // Using XmlStringLookup.secure=false allows the BLA to occur. } @Test void testMissingXPath() { assertThrows(IllegalArgumentException.class, () -> XmlStringLookup.INSTANCE.apply(DOC_RELATIVE + ":!JUNK!")); } @Test void testNoFeatures() { final String xpath = "/root/path/to/node"; assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP).apply(DOC_RELATIVE + ":" + xpath)); assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP).apply(DOC_RELATIVE + ":" + xpath)); assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, CURRENT_PATH, ABSENT_PATH).apply(DOC_RELATIVE + ":" + xpath)); assertEquals(DATA, new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, ABSENT_PATH, CURRENT_PATH).apply(DOC_RELATIVE + ":" + xpath)); assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, ABSENT_PATH).apply(DOC_ROOT + ":" + xpath)); assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, CURRENT_PATH).apply(DOC_ROOT + ":" + xpath)); assertThrows(IllegalArgumentException.class, () -> new XmlStringLookup(EMPTY_MAP, EMPTY_MAP, ABSENT_PATH, CURRENT_PATH).apply(DOC_ROOT + ":" + xpath)); } @Test void testNoFeaturesDefault() { final HashMap features = new HashMap<>(1); features.put(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); assertLookup(new XmlStringLookup(EMPTY_MAP, features)); } @Test void testNull() { assertNull(XmlStringLookup.INSTANCE.apply(null)); } @Test void testOne() { assertLookup(XmlStringLookup.INSTANCE); } @Test void testToString() { // does not blow up and gives some kind of string. assertFalse(XmlStringLookup.INSTANCE.toString().isEmpty()); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/external/000077500000000000000000000000001511432740600317425ustar00rootroot00000000000000CustomStringSubstitutorTest.java000066400000000000000000000034461511432740600403260ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/lookup/external/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.apache.commons.text.lookup.external; import java.io.IOException; import java.nio.file.Paths; import org.apache.commons.text.StringSubstitutor; import org.apache.commons.text.lookup.FileStringLookupTest; import org.apache.commons.text.lookup.PropertiesStringLookupTest; import org.apache.commons.text.lookup.StringLookupFactory; import org.junit.jupiter.api.Test; /** * Tests building a fenced {@link StringSubstitutor} to exclude the use of package-private elements. */ class CustomStringSubstitutorTest { private StringSubstitutor createStringSubstitutor() { final StringLookupFactory factory = StringLookupFactory.builder().setFences(Paths.get("")).get(); return new StringSubstitutor(factory.interpolatorStringLookup()); } @Test void testFencedFiles() throws IOException { FileStringLookupTest.testFence(createStringSubstitutor()); } @Test void testFencedProperties() { PropertiesStringLookupTest.testFence(createStringSubstitutor()); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/matcher/000077500000000000000000000000001511432740600302325ustar00rootroot00000000000000StringMatcherFactoryTest.java000066400000000000000000000153111511432740600357610ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/matcher/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.matcher; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import org.junit.jupiter.api.Test; /** * Tests {@link StringMatcherFactory}. */ class StringMatcherFactoryTest { private static final class StringMatcherDefaults implements StringMatcher { @Override public int isMatch(final char[] buffer, final int start, final int bufferStart, final int bufferEnd) { return 2; } } @Test void test_andMatcher() { assertNotNull(StringMatcherFactory.INSTANCE.andMatcher(StringMatcherFactory.INSTANCE.charMatcher('1'), StringMatcherFactory.INSTANCE.stringMatcher("2"))); assertNotNull(StringMatcherFactory.INSTANCE.andMatcher(null, StringMatcherFactory.INSTANCE.stringMatcher("2"))); assertNotNull(StringMatcherFactory.INSTANCE.andMatcher(null, null)); StringMatcher andMatcher = StringMatcherFactory.INSTANCE.andMatcher(); assertNotNull(andMatcher); assertEquals(0, andMatcher.size()); andMatcher = StringMatcherFactory.INSTANCE.andMatcher(StringMatcherFactory.INSTANCE.charMatcher('1')); assertNotNull(andMatcher); assertEquals(1, andMatcher.size()); } @Test void test_charMatcher() { final StringMatcher charMatcher = StringMatcherFactory.INSTANCE.charMatcher('1'); assertNotNull(charMatcher); assertNotNull(charMatcher.toString()); assertEquals(1, charMatcher.size()); } @Test void test_charSetMatcher_char() { final StringMatcher charSetMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('1'); assertNotNull(charSetMatcher); assertNotNull(charSetMatcher.toString()); assertEquals(1, charSetMatcher.size()); } @Test void test_charSetMatcher_String() { final StringMatcher charSetMatcher = StringMatcherFactory.INSTANCE.charSetMatcher("1"); assertNotNull(charSetMatcher); assertNotNull(charSetMatcher.toString()); assertEquals(1, charSetMatcher.size()); } @Test void test_commaMatcher() { final StringMatcher commaMatcher = StringMatcherFactory.INSTANCE.commaMatcher(); assertNotNull(commaMatcher); assertNotNull(commaMatcher.toString()); assertEquals(1, commaMatcher.size()); } @Test void test_doubleQuoteMatcher() { final StringMatcher doubleQuoteMatcher = StringMatcherFactory.INSTANCE.doubleQuoteMatcher(); assertNotNull(doubleQuoteMatcher); assertNotNull(doubleQuoteMatcher.toString()); assertEquals(1, doubleQuoteMatcher.size()); } @Test void test_noneMatcher() { final StringMatcher noneMatcher = StringMatcherFactory.INSTANCE.noneMatcher(); assertNotNull(noneMatcher); assertNotNull(noneMatcher.toString()); assertEquals(0, noneMatcher.size()); } @Test void test_quoteMatcher() { final StringMatcher quoteMatcher = StringMatcherFactory.INSTANCE.quoteMatcher(); assertNotNull(quoteMatcher); assertNotNull(quoteMatcher.toString()); assertEquals(1, quoteMatcher.size()); } @Test void test_singleQuoteMatcher() { final StringMatcher singleQuoteMatcher = StringMatcherFactory.INSTANCE.singleQuoteMatcher(); assertNotNull(singleQuoteMatcher); assertNotNull(singleQuoteMatcher.toString()); assertEquals(1, singleQuoteMatcher.size()); } @Test void test_spaceMatcher() { final StringMatcher spaceMatcher = StringMatcherFactory.INSTANCE.spaceMatcher(); assertNotNull(spaceMatcher); assertNotNull(spaceMatcher.toString()); assertEquals(1, spaceMatcher.size()); } @Test void test_splitMatcher() { final StringMatcher splitMatcher = StringMatcherFactory.INSTANCE.splitMatcher(); assertNotNull(splitMatcher); assertNotNull(splitMatcher.toString()); assertEquals(1, splitMatcher.size()); } @Test void test_stringMatcher() { StringMatcher stringMatcher = StringMatcherFactory.INSTANCE.stringMatcher("1"); assertNotNull(stringMatcher); assertNotNull(stringMatcher.toString()); assertEquals(1, stringMatcher.size()); // stringMatcher = StringMatcherFactory.INSTANCE.stringMatcher(); assertNotNull(stringMatcher); assertNotNull(stringMatcher.toString()); assertEquals(0, stringMatcher.size()); } @Test void test_stringMatcherChars() { StringMatcher stringMatcher = StringMatcherFactory.INSTANCE.stringMatcher('1', '2'); assertNotNull(stringMatcher); assertNotNull(stringMatcher.toString()); assertEquals(2, stringMatcher.size()); // stringMatcher = StringMatcherFactory.INSTANCE.stringMatcher('1'); assertNotNull(stringMatcher); assertNotNull(stringMatcher.toString()); assertEquals(1, stringMatcher.size()); // stringMatcher = StringMatcherFactory.INSTANCE.stringMatcher(); assertNotNull(stringMatcher); assertNotNull(stringMatcher.toString()); assertEquals(0, stringMatcher.size()); } @Test void test_tabMatcher() { final StringMatcher charMatcher = StringMatcherFactory.INSTANCE.charMatcher('1'); assertNotNull(charMatcher); assertNotNull(charMatcher.toString()); assertEquals(1, charMatcher.size()); } @Test void test_trimMatcher() { final StringMatcher charMatcher = StringMatcherFactory.INSTANCE.charMatcher('1'); assertNotNull(charMatcher); assertNotNull(charMatcher.toString()); assertEquals(1, charMatcher.size()); } @Test void testDefaultMethods() { final StringMatcherDefaults stringMatcher = new StringMatcherDefaults(); assertEquals(0, stringMatcher.size()); assertEquals(2, stringMatcher.isMatch("1", 0)); } } StringMatcherOnCharArrayTest.java000066400000000000000000000411301511432740600365210ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/matcher/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.matcher; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertSame; import org.junit.jupiter.api.Test; /** * Tests {@link StringMatcher}. */ class StringMatcherOnCharArrayTest { private static final char[] INPUT1 = "0,1\t2 3\n\r\f\u0000'\"".toCharArray(); private static final char[] INPUT2 = "abcdef".toCharArray(); private static final int INPUT2_LENGTH = INPUT2.length; private void checkAndMatcher_char(final StringMatcher matcher) { assertEquals(0, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(3, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(0, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(3, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(0, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); } @Test void testAndMatcher_char() { final StringMatcher matcher1 = StringMatcherFactory.INSTANCE.andMatcher(StringMatcherFactory.INSTANCE.charMatcher('c'), StringMatcherFactory.INSTANCE.stringMatcher("de")); assertEquals(3, matcher1.size()); checkAndMatcher_char(matcher1); // final StringMatcher matcher2 = StringMatcherFactory.INSTANCE.andMatcher(null, StringMatcherFactory.INSTANCE.charMatcher('c'), null, StringMatcherFactory.INSTANCE.stringMatcher("de"), null); assertEquals(3, matcher2.size()); checkAndMatcher_char(matcher2); } @Test void testCharMatcher_char() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.charMatcher('c'); assertEquals(1, matcher.size()); // assertEquals(0, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(0, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(1, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(0, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); } @Test void testCharSetMatcher_charArray() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.charSetMatcher("ace".toCharArray()); assertEquals(1, matcher.size()); // assertEquals(1, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(1, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(1, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(1, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); // assertSame(StringMatcherFactory.INSTANCE.charSetMatcher(), StringMatcherFactory.INSTANCE.noneMatcher()); assertSame(StringMatcherFactory.INSTANCE.charSetMatcher((char[]) null), StringMatcherFactory.INSTANCE.noneMatcher()); assertInstanceOf(AbstractStringMatcher.CharMatcher.class, StringMatcherFactory.INSTANCE.charSetMatcher("a".toCharArray())); } @Test void testCharSetMatcher_String() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.charSetMatcher("ace"); assertEquals(1, matcher.size()); // assertEquals(1, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(1, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(1, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(1, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); // assertSame(StringMatcherFactory.INSTANCE.charSetMatcher(""), StringMatcherFactory.INSTANCE.noneMatcher()); assertSame(StringMatcherFactory.INSTANCE.charSetMatcher((String) null), StringMatcherFactory.INSTANCE.noneMatcher()); assertInstanceOf(AbstractStringMatcher.CharMatcher.class, StringMatcherFactory.INSTANCE.charSetMatcher("a")); } @Test void testCommaMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.commaMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.commaMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 0, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 1, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 0)); assertEquals(1, matcher.isMatch(INPUT1, 1)); assertEquals(0, matcher.isMatch(INPUT1, 2)); } @Test void testDoubleQuoteMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.doubleQuoteMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.doubleQuoteMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 11, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 12, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 11)); assertEquals(1, matcher.isMatch(INPUT1, 12)); } @Test void testMatcherIndices() { // remember that the API contract is tight for the isMatch() method // all the onus is on the caller, so invalid inputs are not // the concern of StringMatcher, and are not bugs final StringMatcher matcher = StringMatcherFactory.INSTANCE.stringMatcher("bc"); assertEquals(2, matcher.size()); assertEquals(2, matcher.isMatch(INPUT2, 1, 1, INPUT2_LENGTH)); assertEquals(2, matcher.isMatch(INPUT2, 1, 0, 3)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, 2)); } @Test void testNoneMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.noneMatcher(); assertEquals(0, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.noneMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 0, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 1, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 3, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 5, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 7, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 8, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 9, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 11, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 12, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 0)); assertEquals(0, matcher.isMatch(INPUT1, 1)); assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(0, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(0, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); assertEquals(0, matcher.isMatch(INPUT1, 7)); assertEquals(0, matcher.isMatch(INPUT1, 8)); assertEquals(0, matcher.isMatch(INPUT1, 9)); assertEquals(0, matcher.isMatch(INPUT1, 10)); assertEquals(0, matcher.isMatch(INPUT1, 11)); assertEquals(0, matcher.isMatch(INPUT1, 12)); } @Test void testQuoteMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.quoteMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.quoteMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 11, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 12, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 10)); assertEquals(1, matcher.isMatch(INPUT1, 11)); assertEquals(1, matcher.isMatch(INPUT1, 12)); } @Test void testSingleQuoteMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.singleQuoteMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.singleQuoteMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 11, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 12, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 10)); assertEquals(1, matcher.isMatch(INPUT1, 11)); assertEquals(0, matcher.isMatch(INPUT1, 12)); } @Test void testSpaceMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.spaceMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.spaceMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 5, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(1, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); } @Test void testSplitMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.splitMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.splitMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 3, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 5, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 7, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 8, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 9, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(1, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(1, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); assertEquals(1, matcher.isMatch(INPUT1, 7)); assertEquals(1, matcher.isMatch(INPUT1, 8)); assertEquals(1, matcher.isMatch(INPUT1, 9)); assertEquals(0, matcher.isMatch(INPUT1, 10)); } private void testStringMatcher_String(final StringMatcher matcher) { assertEquals(2, matcher.size()); // assertEquals(0, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(2, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(0, matcher.isMatch(INPUT2, 0)); assertEquals(2, matcher.isMatch(INPUT2, 1)); assertEquals(0, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(0, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); // assertSame(StringMatcherFactory.INSTANCE.stringMatcher(""), StringMatcherFactory.INSTANCE.noneMatcher()); assertSame(StringMatcherFactory.INSTANCE.stringMatcher((String) null), StringMatcherFactory.INSTANCE.noneMatcher()); } @Test void testStringMatcher_String_fromChars() { testStringMatcher_String(StringMatcherFactory.INSTANCE.stringMatcher('b', 'c')); testStringMatcher_String(StringMatcherFactory.INSTANCE.stringMatcher(new char[] { 'b', 'c' })); } @Test void testStringMatcher_String_fromString() { testStringMatcher_String(StringMatcherFactory.INSTANCE.stringMatcher("bc")); } @Test void testTabMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.tabMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.tabMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 3, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(1, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); } @Test void testTrimMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.trimMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.trimMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 3, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 5, 0, INPUT1.length)); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 7, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 8, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 9, 0, INPUT1.length)); assertEquals(1, matcher.isMatch(INPUT1, 10, 0, INPUT1.length)); // assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(1, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(1, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); assertEquals(1, matcher.isMatch(INPUT1, 7)); assertEquals(1, matcher.isMatch(INPUT1, 8)); assertEquals(1, matcher.isMatch(INPUT1, 9)); assertEquals(1, matcher.isMatch(INPUT1, 10)); } } StringMatcherOnCharSequenceStringTest.java000066400000000000000000000405161511432740600404110ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/matcher/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.matcher; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertSame; import org.junit.jupiter.api.Test; /** * Tests {@link StringMatcher}. */ class StringMatcherOnCharSequenceStringTest { private static final String INPUT1 = "0,1\t2 3\n\r\f\u0000'\""; private static final String INPUT2 = "abcdef"; private static final int INPUT2_LENGTH = INPUT2.length(); private void checkAndMatcher_char(final StringMatcher matcher) { assertEquals(0, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(3, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(0, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(3, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(0, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); } @Test void testAndMatcher_char() { final StringMatcher matcher1 = StringMatcherFactory.INSTANCE.andMatcher(StringMatcherFactory.INSTANCE.charMatcher('c'), StringMatcherFactory.INSTANCE.stringMatcher("de")); assertEquals(3, matcher1.size()); checkAndMatcher_char(matcher1); // final StringMatcher matcher2 = StringMatcherFactory.INSTANCE.andMatcher(null, StringMatcherFactory.INSTANCE.charMatcher('c'), null, StringMatcherFactory.INSTANCE.stringMatcher("de"), null); assertEquals(3, matcher2.size()); checkAndMatcher_char(matcher2); } @Test void testCharMatcher_char() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.charMatcher('c'); assertEquals(1, matcher.size()); // assertEquals(0, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(0, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(1, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(0, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); } @Test void testCharSetMatcher_charArray() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.charSetMatcher("ace".toCharArray()); assertEquals(1, matcher.size()); // assertEquals(1, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(1, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(1, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(1, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); // assertSame(StringMatcherFactory.INSTANCE.charSetMatcher(), StringMatcherFactory.INSTANCE.noneMatcher()); assertSame(StringMatcherFactory.INSTANCE.charSetMatcher((char[]) null), StringMatcherFactory.INSTANCE.noneMatcher()); assertInstanceOf(AbstractStringMatcher.CharMatcher.class, StringMatcherFactory.INSTANCE.charSetMatcher("a".toCharArray())); } @Test void testCharSetMatcher_String() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.charSetMatcher("ace"); assertEquals(1, matcher.size()); // assertEquals(1, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(1, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(1, matcher.isMatch(INPUT2, 0)); assertEquals(0, matcher.isMatch(INPUT2, 1)); assertEquals(1, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(1, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); // assertSame(StringMatcherFactory.INSTANCE.charSetMatcher(""), StringMatcherFactory.INSTANCE.noneMatcher()); assertSame(StringMatcherFactory.INSTANCE.charSetMatcher((String) null), StringMatcherFactory.INSTANCE.noneMatcher()); assertInstanceOf(AbstractStringMatcher.CharMatcher.class, StringMatcherFactory.INSTANCE.charSetMatcher("a")); } @Test void testCommaMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.commaMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.commaMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 0, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 1, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 0)); assertEquals(1, matcher.isMatch(INPUT1, 1)); assertEquals(0, matcher.isMatch(INPUT1, 2)); } @Test void testDoubleQuoteMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.doubleQuoteMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.doubleQuoteMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 11, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 12, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 11)); assertEquals(1, matcher.isMatch(INPUT1, 12)); } @Test void testMatcherIndices() { // remember that the API contract is tight for the isMatch() method // all the onus is on the caller, so invalid inputs are not // the concern of StringMatcher, and are not bugs final StringMatcher matcher = StringMatcherFactory.INSTANCE.stringMatcher("bc"); assertEquals(2, matcher.size()); assertEquals(2, matcher.isMatch(INPUT2, 1, 1, INPUT2_LENGTH)); assertEquals(2, matcher.isMatch(INPUT2, 1, 0, 3)); assertEquals(0, matcher.isMatch(INPUT2, 1, 0, 2)); } @Test void testNoneMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.noneMatcher(); assertEquals(0, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.noneMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 0, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 1, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 3, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 5, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 7, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 8, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 9, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 11, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 12, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 0)); assertEquals(0, matcher.isMatch(INPUT1, 1)); assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(0, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(0, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); assertEquals(0, matcher.isMatch(INPUT1, 7)); assertEquals(0, matcher.isMatch(INPUT1, 8)); assertEquals(0, matcher.isMatch(INPUT1, 9)); assertEquals(0, matcher.isMatch(INPUT1, 10)); assertEquals(0, matcher.isMatch(INPUT1, 11)); assertEquals(0, matcher.isMatch(INPUT1, 12)); } @Test void testQuoteMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.quoteMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.quoteMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 11, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 12, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 10)); assertEquals(1, matcher.isMatch(INPUT1, 11)); assertEquals(1, matcher.isMatch(INPUT1, 12)); } @Test void testSingleQuoteMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.singleQuoteMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.singleQuoteMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 11, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 12, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 10)); assertEquals(1, matcher.isMatch(INPUT1, 11)); assertEquals(0, matcher.isMatch(INPUT1, 12)); } @Test void testSpaceMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.spaceMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.spaceMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 5, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(1, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); } @Test void testSplitMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.splitMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.splitMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 3, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 5, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 7, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 8, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 9, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 10, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(1, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(1, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); assertEquals(1, matcher.isMatch(INPUT1, 7)); assertEquals(1, matcher.isMatch(INPUT1, 8)); assertEquals(1, matcher.isMatch(INPUT1, 9)); assertEquals(0, matcher.isMatch(INPUT1, 10)); } @Test void testStringMatcher_String() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.stringMatcher("bc"); assertEquals(2, matcher.size()); // assertEquals(0, matcher.isMatch(INPUT2, 0, 0, INPUT2_LENGTH)); assertEquals(2, matcher.isMatch(INPUT2, 1, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 2, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 3, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 4, 0, INPUT2_LENGTH)); assertEquals(0, matcher.isMatch(INPUT2, 5, 0, INPUT2_LENGTH)); // assertEquals(0, matcher.isMatch(INPUT2, 0)); assertEquals(2, matcher.isMatch(INPUT2, 1)); assertEquals(0, matcher.isMatch(INPUT2, 2)); assertEquals(0, matcher.isMatch(INPUT2, 3)); assertEquals(0, matcher.isMatch(INPUT2, 4)); assertEquals(0, matcher.isMatch(INPUT2, 5)); // assertSame(StringMatcherFactory.INSTANCE.stringMatcher(""), StringMatcherFactory.INSTANCE.noneMatcher()); assertSame(StringMatcherFactory.INSTANCE.stringMatcher((String) null), StringMatcherFactory.INSTANCE.noneMatcher()); } @Test void testTabMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.tabMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.tabMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 3, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(1, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); } @Test void testTrimMatcher() { final StringMatcher matcher = StringMatcherFactory.INSTANCE.trimMatcher(); assertEquals(1, matcher.size()); assertSame(StringMatcherFactory.INSTANCE.trimMatcher(), matcher); // assertEquals(0, matcher.isMatch(INPUT1, 2, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 3, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 4, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 5, 0, INPUT1.length())); assertEquals(0, matcher.isMatch(INPUT1, 6, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 7, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 8, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 9, 0, INPUT1.length())); assertEquals(1, matcher.isMatch(INPUT1, 10, 0, INPUT1.length())); // assertEquals(0, matcher.isMatch(INPUT1, 2)); assertEquals(1, matcher.isMatch(INPUT1, 3)); assertEquals(0, matcher.isMatch(INPUT1, 4)); assertEquals(1, matcher.isMatch(INPUT1, 5)); assertEquals(0, matcher.isMatch(INPUT1, 6)); assertEquals(1, matcher.isMatch(INPUT1, 7)); assertEquals(1, matcher.isMatch(INPUT1, 8)); assertEquals(1, matcher.isMatch(INPUT1, 9)); assertEquals(1, matcher.isMatch(INPUT1, 10)); } } StringSubstitutorGetSetTest.java000066400000000000000000000104231511432740600365300ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/matcher/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.matcher; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.apache.commons.text.StringSubstitutor; import org.junit.jupiter.api.Test; /** * Test class for {@link StringSubstitutor}. */ class StringSubstitutorGetSetTest { /** * Tests get set. */ @Test void testGetSetPrefix() { final StringSubstitutor sub = new StringSubstitutor(); assertTrue(sub.getVariablePrefixMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); sub.setVariablePrefix('<'); assertTrue(sub.getVariablePrefixMatcher() instanceof AbstractStringMatcher.CharMatcher); sub.setVariablePrefix("<<"); assertTrue(sub.getVariablePrefixMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefix((String) null)); assertTrue(sub.getVariablePrefixMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); final StringMatcher matcher = StringMatcherFactory.INSTANCE.commaMatcher(); sub.setVariablePrefixMatcher(matcher); assertSame(matcher, sub.getVariablePrefixMatcher()); assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefixMatcher((StringMatcher) null)); assertSame(matcher, sub.getVariablePrefixMatcher()); } /** * Tests get set. */ @Test void testGetSetSuffix() { final StringSubstitutor sub = new StringSubstitutor(); assertTrue(sub.getVariableSuffixMatcher() instanceof AbstractStringMatcher.CharMatcher); sub.setVariableSuffix('<'); assertTrue(sub.getVariableSuffixMatcher() instanceof AbstractStringMatcher.CharMatcher); sub.setVariableSuffix("<<"); assertTrue(sub.getVariableSuffixMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffix((String) null)); assertTrue(sub.getVariableSuffixMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); final StringMatcher matcher = StringMatcherFactory.INSTANCE.commaMatcher(); sub.setVariableSuffixMatcher(matcher); assertSame(matcher, sub.getVariableSuffixMatcher()); assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffixMatcher((StringMatcher) null)); assertSame(matcher, sub.getVariableSuffixMatcher()); } /** * Tests get set. */ @Test void testGetSetValueDelimiter() { final StringSubstitutor sub = new StringSubstitutor(); assertTrue(sub.getValueDelimiterMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); sub.setValueDelimiter(':'); assertTrue(sub.getValueDelimiterMatcher() instanceof AbstractStringMatcher.CharMatcher); sub.setValueDelimiter("||"); assertTrue(sub.getValueDelimiterMatcher() instanceof AbstractStringMatcher.CharArrayMatcher); sub.setValueDelimiter((String) null); assertNull(sub.getValueDelimiterMatcher()); final StringMatcher matcher = StringMatcherFactory.INSTANCE.commaMatcher(); sub.setValueDelimiterMatcher(matcher); assertSame(matcher, sub.getValueDelimiterMatcher()); sub.setValueDelimiterMatcher((StringMatcher) null); assertNull(sub.getValueDelimiterMatcher()); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/numbers/000077500000000000000000000000001511432740600302625ustar00rootroot00000000000000DoubleFormatTest.java000066400000000000000000000643441511432740600343040ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/numbers/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.numbers; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; import java.util.Random; import java.util.function.DoubleFunction; import java.util.function.Function; import java.util.stream.Stream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class DoubleFormatTest { private static void assertLocalizedFormatsAreEqual(final double d, final DecimalFormat df, final DoubleFunction fmt, final Locale loc) { // NOTE: Perform the string comparison only on non-format characters. This is required because // JDK 16 adds directionality characters to strings for certain locales, such as Arabic, whereas // previous JDKs do not. We will match the behavior of the previous versions here and ignore formatting // for test purposes. final String dfStr = trimFormatChars(df.format(d)); final String fmtStr = trimFormatChars(fmt.apply(d)); try { Assertions.assertEquals(dfStr, fmtStr, () -> "Unexpected output for locale [" + loc.toLanguageTag() + "] and double value " + d); } catch (final AssertionError e) { // Note: // The DecimalFormat may omit the fraction component if it is zero // when using the ENGINEERING format "##0.0##E0". // e.g. new DecimalFormat("##0.0##E0").format(1.1299999e-4) => 113E-6. // The DoubleFormat class either always includes the zero or removes it // with the setting includeFractionPlaceholder(false). // Since we expect this mismatch we can remove the decimal point followed // by a zero from the DoubleFormat output. // This effectively checks: abcExyz == abc.0Exyz final DecimalFormatSymbols dfs = new DecimalFormatSymbols(loc); final char decimalSeparator = dfs.getDecimalSeparator(); final char zeroDigit = dfs.getZeroDigit(); final String updated = fmtStr.replace(new String(new char[] {decimalSeparator, zeroDigit}), ""); if (dfStr.equals(updated)) { return; } throw e; } } private static void checkDefaultFormatSpecial(final DoubleFunction fmt) { checkFormat(fmt, 0.0, "0.0"); checkFormat(fmt, -0.0, "-0.0"); checkFormat(fmt, Double.NaN, "NaN"); checkFormat(fmt, Double.POSITIVE_INFINITY, "Infinity"); checkFormat(fmt, Double.NEGATIVE_INFINITY, "-Infinity"); } private static void checkFormat(final DoubleFunction fmt, final double d, final String str) { Assertions.assertEquals(str, fmt.apply(d)); } /** * Check that the given double value can be exactly recovered from formatted string representation * produced by the format instance. * @param fmt format instance * @param d input double value */ private static void checkFormatAccuracy(final DoubleFunction fmt, final double d) { final String str = fmt.apply(d); final double parsed = Double.parseDouble(str); Assertions.assertEquals(d, parsed, () -> "Formatted double string [" + str + "] did not match input value"); } /** * Check that the given format type correctly formats doubles when using the * default configuration options. The format itself is not checked; only the * fact that the input double can be successfully recovered using {@link Double#parseDouble(String)} * is asserted. * @param type format type */ private static void checkFormatAccuracyWithDefaults(final DoubleFormat type) { final DoubleFunction fmt = type.builder().get(); checkDefaultFormatSpecial(fmt); checkFormatAccuracy(fmt, Double.MIN_VALUE); checkFormatAccuracy(fmt, -Double.MIN_VALUE); checkFormatAccuracy(fmt, Double.MIN_NORMAL); checkFormatAccuracy(fmt, -Double.MIN_NORMAL); checkFormatAccuracy(fmt, Double.MAX_VALUE); checkFormatAccuracy(fmt, -Double.MAX_VALUE); checkFormatAccuracy(fmt, Math.PI); checkFormatAccuracy(fmt, Math.E); final Random rnd = new Random(10L); final int cnt = 1000; for (int i = 0; i < cnt; ++i) { checkFormatAccuracy(fmt, randomDouble(rnd)); } } private static void checkLocalizedFormat(final Locale loc, final String pattern, final Function> factory) { // arrange final DecimalFormat df = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(loc)); final DoubleFunction fmt = factory.apply(loc); // act/assert assertLocalizedFormatsAreEqual(0.0, df, fmt, loc); assertLocalizedFormatsAreEqual(Double.POSITIVE_INFINITY, df, fmt, loc); assertLocalizedFormatsAreEqual(Double.NEGATIVE_INFINITY, df, fmt, loc); assertLocalizedFormatsAreEqual(Double.NaN, df, fmt, loc); assertLocalizedFormatsAreEqual(1.0, df, fmt, loc); assertLocalizedFormatsAreEqual(-1.0, df, fmt, loc); assertLocalizedFormatsAreEqual(Math.PI, df, fmt, loc); assertLocalizedFormatsAreEqual(Math.E, df, fmt, loc); // Locales are tested using: // DecimalFormat DoubleFormat // ##0.0##E0 : ENGINEERING maPrecision=6 // 0.0## : PLAIN minDecimalExponent(-3) // #,##0.0## : PLAIN minDecimalExponent(-3) // 0.0##E0 : SCIENTIFIC maPrecision=4 // The data should not test full precision (17 digits) of the PLAIN format. // Set the exponent range to create decimals with exponents of approximately // 10^7 to 10^-7: log2(1e7) = 23.25. final Random rnd = new Random(12L); final int minExp = -24; final int maxExp = 24; final int cnt = 1000; for (int i = 0; i < cnt; ++i) { assertLocalizedFormatsAreEqual(randomDouble(minExp, maxExp, rnd), df, fmt, loc); } } private static void checkLocalizedFormats(final String pattern, final Function> factory) { for (final Locale loc : Locale.getAvailableLocales()) { checkLocalizedFormat(loc, pattern, factory); } } /** * Create a random double value with exponent in the range {@code [minExp, maxExp]}. * @param minExp minimum exponent; must be less than {@code maxExp} * @param maxExp maximum exponent; must be greater than {@code minExp} * @param rnd random number generator * @return random double */ private static double randomDouble(final int minExp, final int maxExp, final Random rnd) { // Create random doubles using random bits in the sign bit and the mantissa. final long mask = (1L << 52) - 1 | 1L << 63; final long bits = rnd.nextLong() & mask; // The exponent must be unsigned so + 1023 to the signed exponent final long exp = rnd.nextInt(maxExp - minExp + 1) + minExp + 1023; return Double.longBitsToDouble(bits | exp << 52); } /** * Create a random double value using the full range of exponent values. * @param rnd random number generator * @return random double */ private static double randomDouble(final Random rnd) { return randomDouble(Double.MIN_EXPONENT, Double.MAX_EXPONENT, rnd); } static Stream testMaximumPrecision() { return Stream.of( // Example of different Double.toString representations across JDKs // JDK 17: -9.3540047119774374E17 // JDK 21: -9.354004711977437E17 Arguments.of(DoubleFormat.PLAIN.builder().get(), -9.3540047119774374E17), Arguments.of(DoubleFormat.SCIENTIFIC.builder().get(), -9.3540047119774374E17) ); } /** * Remove Unicode {@link Character#FORMAT format} characters from the given string. * @param str input string * @return input string with format characters removed */ private static String trimFormatChars(final String str) { final StringBuilder sb = new StringBuilder(); for (final char c : str.toCharArray()) { if (Character.getType(c) != Character.FORMAT) { sb.append(c); } } return sb.toString(); } @Test void testBuilder_illegalArgs() { // arrange final DoubleFormat.Builder builder = DoubleFormat.PLAIN.builder(); // act/assert Assertions.assertThrows(NullPointerException.class, () -> builder.digits(null)); Assertions.assertThrows(IllegalArgumentException.class, () -> builder.digits("a")); Assertions.assertThrows(IllegalArgumentException.class, () -> builder.digits("0123456789a")); Assertions.assertThrows(NullPointerException.class, () -> builder.exponentSeparator(null)); Assertions.assertThrows(NullPointerException.class, () -> builder.infinity(null)); Assertions.assertThrows(NullPointerException.class, () -> builder.nan(null)); Assertions.assertThrows(NullPointerException.class, () -> builder.formatSymbols(null)); } @Test void testCustomDigitString() { // arrange final String digits = "abcdefghij"; final DoubleFunction plain = DoubleFormat.PLAIN.builder().digits(digits).get(); final DoubleFunction sci = DoubleFormat.SCIENTIFIC.builder().digits(digits).get(); final DoubleFunction eng = DoubleFormat.ENGINEERING.builder().digits(digits).get(); final DoubleFunction mixed = DoubleFormat.MIXED.builder().digits(digits).get(); // act/assert checkFormat(plain, 9876543210.0, "jihgfedcba.a"); checkFormat(sci, 9876543210.0, "j.ihgfedcbEj"); checkFormat(eng, 9876543210.0, "j.ihgfedcbEj"); checkFormat(mixed, 9876543210.0, "j.ihgfedcbEj"); } @Test void testEngineering_custom() { // act final DoubleFunction fmt = DoubleFormat.ENGINEERING.builder() .maxPrecision(3) .minDecimalExponent(-3) .allowSignedZero(false) .includeFractionPlaceholder(false) .decimalSeparator(',') .exponentSeparator("e") .infinity("inf") .nan("nan") .minusSign('!') .get(); // act/assert checkFormat(fmt, Double.NaN, "nan"); checkFormat(fmt, Double.POSITIVE_INFINITY, "inf"); checkFormat(fmt, Double.NEGATIVE_INFINITY, "!inf"); checkFormat(fmt, 0.00001, "0"); checkFormat(fmt, -0.0001, "0"); checkFormat(fmt, 0.001, "1e!3"); checkFormat(fmt, -0.01, "!10e!3"); checkFormat(fmt, 0.1, "100e!3"); checkFormat(fmt, -0.0, "0"); checkFormat(fmt, 0.0, "0"); checkFormat(fmt, -1.0, "!1"); checkFormat(fmt, 10.0, "10"); checkFormat(fmt, -100.0, "!100"); checkFormat(fmt, 1000.0, "1e3"); checkFormat(fmt, -10000.0, "!10e3"); checkFormat(fmt, 100000.0, "100e3"); checkFormat(fmt, -1000000.0, "!1e6"); checkFormat(fmt, 10000000.0, "10e6"); checkFormat(fmt, -100000000.0, "!100e6"); checkFormat(fmt, 1.25e-3, "1e!3"); checkFormat(fmt, -9.975e-4, "!1e!3"); checkFormat(fmt, 12345, "12,3e3"); checkFormat(fmt, -9_999_999, "!10e6"); checkFormat(fmt, 1.00001e7, "10e6"); checkFormat(fmt, Double.MAX_VALUE, "180e306"); checkFormat(fmt, Double.MIN_VALUE, "0"); checkFormat(fmt, Double.MIN_NORMAL, "0"); checkFormat(fmt, Math.PI, "3,14"); checkFormat(fmt, Math.E, "2,72"); } @Test void testEngineering_defaults() { // act final DoubleFunction fmt = DoubleFormat.ENGINEERING.builder() .get(); // act/assert checkDefaultFormatSpecial(fmt); checkFormat(fmt, 0.00001, "10.0E-6"); checkFormat(fmt, -0.0001, "-100.0E-6"); checkFormat(fmt, 0.001, "1.0E-3"); checkFormat(fmt, -0.01, "-10.0E-3"); checkFormat(fmt, 0.1, "100.0E-3"); checkFormat(fmt, -0.0, "-0.0"); checkFormat(fmt, 0.0, "0.0"); checkFormat(fmt, -1.0, "-1.0"); checkFormat(fmt, 10.0, "10.0"); checkFormat(fmt, -100.0, "-100.0"); checkFormat(fmt, 1000.0, "1.0E3"); checkFormat(fmt, -10000.0, "-10.0E3"); checkFormat(fmt, 100000.0, "100.0E3"); checkFormat(fmt, -1000000.0, "-1.0E6"); checkFormat(fmt, 10000000.0, "10.0E6"); checkFormat(fmt, -100000000.0, "-100.0E6"); checkFormat(fmt, 1.25e-3, "1.25E-3"); checkFormat(fmt, -9.975e-4, "-997.5E-6"); checkFormat(fmt, 12345, "12.345E3"); checkFormat(fmt, -9_999_999, "-9.999999E6"); checkFormat(fmt, 1.00001e7, "10.0001E6"); checkFormat(fmt, Double.MAX_VALUE, "179.76931348623157E306"); checkFormat(fmt, Double.MIN_VALUE, "4.9E-324"); checkFormat(fmt, Double.MIN_NORMAL, "22.250738585072014E-309"); checkFormat(fmt, Math.PI, "3.141592653589793"); checkFormat(fmt, Math.E, "2.718281828459045"); } @Test void testEngineering_localeFormatComparison() { // act/assert checkLocalizedFormats("##0.0##E0", loc -> DoubleFormat.ENGINEERING.builder() .maxPrecision(6) .alwaysIncludeExponent(true) .formatSymbols(DecimalFormatSymbols.getInstance(loc)) .get()); } @Test void testFormatAccuracy() { // act/assert checkFormatAccuracyWithDefaults(DoubleFormat.PLAIN); checkFormatAccuracyWithDefaults(DoubleFormat.MIXED); checkFormatAccuracyWithDefaults(DoubleFormat.SCIENTIFIC); checkFormatAccuracyWithDefaults(DoubleFormat.ENGINEERING); } /** * Test formatting at the maximum precision. The formatting is based on the output * of {@link Double#toString()}. If cannot create an extended precision text * representation and is limited to 17 significant digits. This test verifies that * formatting does not lose information that would be required to recreate the * same double value. */ @ParameterizedTest @MethodSource void testMaximumPrecision(final DoubleFunction fmt, final double value) { final String s = fmt.apply(value); final double d = Double.parseDouble(s); Assertions.assertEquals(value, d, () -> value + " formatted as " + s); } @Test void testMixed_custom() { // arrange final DoubleFunction fmt = DoubleFormat.MIXED.builder() .maxPrecision(3) .minDecimalExponent(-3) .allowSignedZero(false) .includeFractionPlaceholder(false) .decimalSeparator(',') .plainFormatMaxDecimalExponent(4) .plainFormatMinDecimalExponent(-1) .exponentSeparator("e") .infinity("inf") .nan("nan") .minusSign('!') .get(); // act/assert checkFormat(fmt, Double.NaN, "nan"); checkFormat(fmt, Double.POSITIVE_INFINITY, "inf"); checkFormat(fmt, Double.NEGATIVE_INFINITY, "!inf"); checkFormat(fmt, 0.00001, "0"); checkFormat(fmt, -0.0001, "0"); checkFormat(fmt, 0.001, "1e!3"); checkFormat(fmt, -0.01, "!1e!2"); checkFormat(fmt, 0.1, "0,1"); checkFormat(fmt, -0.0, "0"); checkFormat(fmt, 0.0, "0"); checkFormat(fmt, -1.0, "!1"); checkFormat(fmt, 10.0, "10"); checkFormat(fmt, -100.0, "!100"); checkFormat(fmt, 1000.0, "1000"); checkFormat(fmt, -10000.0, "!10000"); checkFormat(fmt, 100000.0, "1e5"); checkFormat(fmt, -1000000.0, "!1e6"); checkFormat(fmt, 10000000.0, "1e7"); checkFormat(fmt, -100000000.0, "!1e8"); checkFormat(fmt, 1.25e-3, "1e!3"); checkFormat(fmt, -9.975e-4, "!1e!3"); checkFormat(fmt, 12345, "12300"); checkFormat(fmt, -9_999_999, "!1e7"); checkFormat(fmt, 1.00001e7, "1e7"); checkFormat(fmt, Double.MAX_VALUE, "1,8e308"); checkFormat(fmt, Double.MIN_VALUE, "0"); checkFormat(fmt, Double.MIN_NORMAL, "0"); checkFormat(fmt, Math.PI, "3,14"); checkFormat(fmt, Math.E, "2,72"); } @Test void testMixed_defaults() { // arrange testMixed_defaults(DoubleFormat.MIXED.builder().get()); } private void testMixed_defaults(final DoubleFunction fmt) { // act/assert checkDefaultFormatSpecial(fmt); checkFormat(fmt, 0.00001, "1.0E-5"); checkFormat(fmt, -0.0001, "-1.0E-4"); checkFormat(fmt, 0.001, "0.001"); checkFormat(fmt, -0.01, "-0.01"); checkFormat(fmt, 0.1, "0.1"); checkFormat(fmt, -0.0, "-0.0"); checkFormat(fmt, 0.0, "0.0"); checkFormat(fmt, -1.0, "-1.0"); checkFormat(fmt, 10.0, "10.0"); checkFormat(fmt, -100.0, "-100.0"); checkFormat(fmt, 1000.0, "1000.0"); checkFormat(fmt, -10000.0, "-10000.0"); checkFormat(fmt, 100000.0, "100000.0"); checkFormat(fmt, -1000000.0, "-1000000.0"); checkFormat(fmt, 10000000.0, "1.0E7"); checkFormat(fmt, -100000000.0, "-1.0E8"); checkFormat(fmt, 1.25e-3, "0.00125"); checkFormat(fmt, -9.975e-4, "-9.975E-4"); checkFormat(fmt, 12345, "12345.0"); checkFormat(fmt, -9_999_999, "-9999999.0"); checkFormat(fmt, 1.00001e7, "1.00001E7"); checkFormat(fmt, Double.MAX_VALUE, "1.7976931348623157E308"); checkFormat(fmt, Double.MIN_VALUE, "4.9E-324"); checkFormat(fmt, Double.MIN_NORMAL, "2.2250738585072014E-308"); checkFormat(fmt, Math.PI, "3.141592653589793"); checkFormat(fmt, Math.E, "2.718281828459045"); } @Test void testMixed_defaultsDeprecated() { testMixed_defaults(DoubleFormat.MIXED.builder().build()); } @Test void testPlain_custom() { // arrange final DoubleFunction fmt = DoubleFormat.PLAIN.builder() .maxPrecision(3) .minDecimalExponent(-3) .allowSignedZero(false) .includeFractionPlaceholder(false) .decimalSeparator(',') .exponentSeparator("e") .infinity("inf") .nan("nan") .minusSign('!') .get(); // act/assert checkFormat(fmt, Double.NaN, "nan"); checkFormat(fmt, Double.POSITIVE_INFINITY, "inf"); checkFormat(fmt, Double.NEGATIVE_INFINITY, "!inf"); checkFormat(fmt, 0.00001, "0"); checkFormat(fmt, -0.0001, "0"); checkFormat(fmt, 0.001, "0,001"); checkFormat(fmt, -0.01, "!0,01"); checkFormat(fmt, 0.1, "0,1"); checkFormat(fmt, -0.0, "0"); checkFormat(fmt, 0.0, "0"); checkFormat(fmt, -1.0, "!1"); checkFormat(fmt, 10.0, "10"); checkFormat(fmt, -100.0, "!100"); checkFormat(fmt, 1000.0, "1000"); checkFormat(fmt, -10000.0, "!10000"); checkFormat(fmt, 100000.0, "100000"); checkFormat(fmt, -1000000.0, "!1000000"); checkFormat(fmt, 10000000.0, "10000000"); checkFormat(fmt, -100000000.0, "!100000000"); checkFormat(fmt, 1.25e-3, "0,001"); checkFormat(fmt, -9.975e-4, "!0,001"); checkFormat(fmt, 12345, "12300"); checkFormat(fmt, -9_999_999, "!10000000"); checkFormat(fmt, 1.00001e7, "10000000"); checkFormat(fmt, Float.MAX_VALUE, "340000000000000000000000000000000000000"); checkFormat(fmt, -Float.MIN_VALUE, "0"); checkFormat(fmt, Float.MIN_NORMAL, "0"); checkFormat(fmt, Math.PI, "3,14"); checkFormat(fmt, Math.E, "2,72"); } @Test void testPlain_defaults() { // arrange final DoubleFunction fmt = DoubleFormat.PLAIN.builder() .get(); // act/assert checkFormat(fmt, 0.00001, "0.00001"); checkFormat(fmt, -0.0001, "-0.0001"); checkFormat(fmt, 0.001, "0.001"); checkFormat(fmt, -0.01, "-0.01"); checkFormat(fmt, 0.1, "0.1"); checkFormat(fmt, -0.0, "-0.0"); checkFormat(fmt, 0.0, "0.0"); checkFormat(fmt, -1.0, "-1.0"); checkFormat(fmt, 10.0, "10.0"); checkFormat(fmt, -100.0, "-100.0"); checkFormat(fmt, 1000.0, "1000.0"); checkFormat(fmt, -10000.0, "-10000.0"); checkFormat(fmt, 100000.0, "100000.0"); checkFormat(fmt, -1000000.0, "-1000000.0"); checkFormat(fmt, 10000000.0, "10000000.0"); checkFormat(fmt, -100000000.0, "-100000000.0"); checkFormat(fmt, 1.25e-3, "0.00125"); checkFormat(fmt, -9.975e-4, "-0.0009975"); checkFormat(fmt, 12345, "12345.0"); checkFormat(fmt, -9_999_999, "-9999999.0"); checkFormat(fmt, 1.00001e7, "10000100.0"); checkFormat(fmt, Float.MAX_VALUE, "340282346638528860000000000000000000000.0"); checkFormat(fmt, -Float.MIN_VALUE, "-0.000000000000000000000000000000000000000000001401298464324817"); checkFormat(fmt, Float.MIN_NORMAL, "0.000000000000000000000000000000000000011754943508222875"); checkFormat(fmt, Math.PI, "3.141592653589793"); checkFormat(fmt, Math.E, "2.718281828459045"); } @Test void testPlain_localeFormatComparison() { // act/assert checkLocalizedFormats("0.0##", loc -> DoubleFormat.PLAIN.builder() .minDecimalExponent(-3) .formatSymbols(DecimalFormatSymbols.getInstance(loc)) .get()); checkLocalizedFormats("#,##0.0##", loc -> DoubleFormat.PLAIN.builder() .minDecimalExponent(-3) .groupThousands(true) .formatSymbols(DecimalFormatSymbols.getInstance(loc)) .get()); } @Test void testScientific_custom() { // arrange final DoubleFunction fmt = DoubleFormat.SCIENTIFIC.builder() .maxPrecision(3) .minDecimalExponent(-3) .allowSignedZero(false) .includeFractionPlaceholder(false) .decimalSeparator(',') .exponentSeparator("e") .infinity("inf") .nan("nan") .minusSign('!') .get(); // act/assert checkFormat(fmt, Double.NaN, "nan"); checkFormat(fmt, Double.POSITIVE_INFINITY, "inf"); checkFormat(fmt, Double.NEGATIVE_INFINITY, "!inf"); checkFormat(fmt, 0.00001, "0"); checkFormat(fmt, -0.0001, "0"); checkFormat(fmt, 0.001, "1e!3"); checkFormat(fmt, -0.01, "!1e!2"); checkFormat(fmt, 0.1, "1e!1"); checkFormat(fmt, -0.0, "0"); checkFormat(fmt, 0.0, "0"); checkFormat(fmt, -1.0, "!1"); checkFormat(fmt, 10.0, "1e1"); checkFormat(fmt, -100.0, "!1e2"); checkFormat(fmt, 1000.0, "1e3"); checkFormat(fmt, -10000.0, "!1e4"); checkFormat(fmt, 100000.0, "1e5"); checkFormat(fmt, -1000000.0, "!1e6"); checkFormat(fmt, 10000000.0, "1e7"); checkFormat(fmt, -100000000.0, "!1e8"); checkFormat(fmt, 1.25e-3, "1e!3"); checkFormat(fmt, -9.975e-4, "!1e!3"); checkFormat(fmt, 12345, "1,23e4"); checkFormat(fmt, -9_999_999, "!1e7"); checkFormat(fmt, 1.00001e7, "1e7"); checkFormat(fmt, Double.MAX_VALUE, "1,8e308"); checkFormat(fmt, Double.MIN_VALUE, "0"); checkFormat(fmt, Double.MIN_NORMAL, "0"); checkFormat(fmt, Math.PI, "3,14"); checkFormat(fmt, Math.E, "2,72"); } @Test void testScientific_defaults() { // arrange final DoubleFunction fmt = DoubleFormat.SCIENTIFIC.builder().get(); // act/assert checkDefaultFormatSpecial(fmt); checkFormat(fmt, 0.00001, "1.0E-5"); checkFormat(fmt, -0.0001, "-1.0E-4"); checkFormat(fmt, 0.001, "1.0E-3"); checkFormat(fmt, -0.01, "-1.0E-2"); checkFormat(fmt, 0.1, "1.0E-1"); checkFormat(fmt, -0.0, "-0.0"); checkFormat(fmt, 0.0, "0.0"); checkFormat(fmt, -1.0, "-1.0"); checkFormat(fmt, 10.0, "1.0E1"); checkFormat(fmt, -100.0, "-1.0E2"); checkFormat(fmt, 1000.0, "1.0E3"); checkFormat(fmt, -10000.0, "-1.0E4"); checkFormat(fmt, 100000.0, "1.0E5"); checkFormat(fmt, -1000000.0, "-1.0E6"); checkFormat(fmt, 10000000.0, "1.0E7"); checkFormat(fmt, -100000000.0, "-1.0E8"); checkFormat(fmt, 1.25e-3, "1.25E-3"); checkFormat(fmt, -9.975e-4, "-9.975E-4"); checkFormat(fmt, 12345, "1.2345E4"); checkFormat(fmt, -9_999_999, "-9.999999E6"); checkFormat(fmt, 1.00001e7, "1.00001E7"); checkFormat(fmt, Double.MAX_VALUE, "1.7976931348623157E308"); checkFormat(fmt, Double.MIN_VALUE, "4.9E-324"); checkFormat(fmt, Double.MIN_NORMAL, "2.2250738585072014E-308"); checkFormat(fmt, Math.PI, "3.141592653589793"); checkFormat(fmt, Math.E, "2.718281828459045"); } @Test void testScientific_localeFormatComparison() { // act/assert checkLocalizedFormats("0.0##E0", loc -> DoubleFormat.SCIENTIFIC.builder() .maxPrecision(4) .alwaysIncludeExponent(true) .formatSymbols(DecimalFormatSymbols.getInstance(loc)) .get()); } } ParsedDecimalTest.java000066400000000000000000000656361511432740600344230ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/numbers/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.numbers; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.util.function.BiFunction; import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.simple.RandomSource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; class ParsedDecimalTest { private static final class FormatOptionsImpl implements ParsedDecimal.FormatOptions { private boolean includeFractionPlaceholder = true; private boolean signedZero = true; private char[] digits = "0123456789".toCharArray(); private char decimalSeparator = '.'; private char thousandsGroupingSeparator = ','; private boolean groupThousands; private char minusSign = '-'; private String exponentSeparator = "E"; private boolean alwaysIncludeExponent; @Override public char getDecimalSeparator() { return decimalSeparator; } @Override public char[] getDigits() { return digits; } @Override public char[] getExponentSeparatorChars() { return exponentSeparator.toCharArray(); } @Override public char getGroupingSeparator() { return thousandsGroupingSeparator; } @Override public char getMinusSign() { return minusSign; } @Override public boolean isAlwaysIncludeExponent() { return alwaysIncludeExponent; } @Override public boolean isGroupThousands() { return groupThousands; } @Override public boolean isIncludeFractionPlaceholder() { return includeFractionPlaceholder; } @Override public boolean isSignedZero() { return signedZero; } public void setAlwaysIncludeExponent(final boolean alwaysIncludeExponent) { this.alwaysIncludeExponent = alwaysIncludeExponent; } public void setDecimalSeparator(final char decimalSeparator) { this.decimalSeparator = decimalSeparator; } public void setDigitsFromString(final String digits) { this.digits = digits.toCharArray(); } public void setExponentSeparator(final String exponentSeparator) { this.exponentSeparator = exponentSeparator; } public void setGroupThousands(final boolean groupThousands) { this.groupThousands = groupThousands; } public void setIncludeFractionPlaceholder(final boolean includeFractionPlaceholder) { this.includeFractionPlaceholder = includeFractionPlaceholder; } public void setMinusSign(final char minusSign) { this.minusSign = minusSign; } public void setSignedZero(final boolean signedZero) { this.signedZero = signedZero; } public void setThousandsGroupingSeparator(final char thousandsGroupingSeparator) { this.thousandsGroupingSeparator = thousandsGroupingSeparator; } } private static void assertMaxPrecision(final double d, final int maxPrecision, final boolean negative, final String digits, final int exponent) { final ParsedDecimal dec = ParsedDecimal.from(d); dec.maxPrecision(maxPrecision); assertSimpleDecimal(dec, negative, digits, exponent); } private static void assertRound(final double d, final int roundExponent, final boolean negative, final String digits, final int exponent) { final ParsedDecimal dec = ParsedDecimal.from(d); dec.round(roundExponent); assertSimpleDecimal(dec, negative, digits, exponent); } private static void assertSimpleDecimal(final ParsedDecimal parsed, final boolean negative, final String digits, final int exponent) { Assertions.assertEquals(negative, parsed.negative); Assertions.assertEquals(digits, digitString(parsed)); Assertions.assertEquals(exponent, parsed.getExponent()); Assertions.assertEquals(digits.length(), parsed.digitCount); Assertions.assertEquals(exponent, parsed.getScientificExponent() - digits.length() + 1); } private static void assertThrowsWithMessage(final Executable fn, final Class type, final String msg) { final Throwable exc = Assertions.assertThrows(type, fn); Assertions.assertEquals(msg, exc.getMessage()); } private static void checkFrom(final double d, final String digits, final int exponent) { final boolean negative = Math.signum(d) < 0; assertSimpleDecimal(ParsedDecimal.from(d), negative, digits, exponent); assertSimpleDecimal(ParsedDecimal.from(-d), !negative, digits, exponent); } private static void checkToEngineeringString(final double d, final String expected, final ParsedDecimal.FormatOptions opts) { checkToStringMethod(d, expected, ParsedDecimal::toEngineeringString, opts); // check the exponent value to make sure it is a multiple of 3 final String pos = ParsedDecimal.from(d).toEngineeringString(opts); Assertions.assertEquals(0, parseExponent(pos, opts) % 3); final String neg = ParsedDecimal.from(-d).toEngineeringString(opts); Assertions.assertEquals(0, parseExponent(neg, opts) % 3); } private static void checkToPlainString(final double d, final String expected, final ParsedDecimal.FormatOptions opts) { checkToStringMethod(d, expected, ParsedDecimal::toPlainString, opts); } private static void checkToScientificString(final double d, final String expected, final ParsedDecimal.FormatOptions opts) { checkToStringMethod(d, expected, ParsedDecimal::toScientificString, opts); } private static void checkToStringMethod(final double d, final String expected, final BiFunction fn, final ParsedDecimal.FormatOptions opts) { final ParsedDecimal pos = ParsedDecimal.from(d); final String actual = fn.apply(pos, opts); Assertions.assertEquals(expected, actual); } private static double createRandomDouble(final UniformRandomProvider rng) { final long mask = (1L << 52) - 1 | 1L << 63; final long bits = rng.nextLong() & mask; final long exp = rng.nextInt(2045) + 1; return Double.longBitsToDouble(bits | exp << 52); } /** Gets the raw digits in the given decimal as a string. * @param dec decimal instancE * @return decimal digits as a string */ private static String digitString(final ParsedDecimal dec) { final StringBuilder sb = new StringBuilder(); for (int i = 0; i < dec.digitCount; ++i) { sb.append(dec.digits[i]); } return sb.toString(); } private static int parseExponent(final String str, final ParsedDecimal.FormatOptions opts) { final char[] expSep = opts.getExponentSeparatorChars(); final int expStartIdx = str.indexOf(String.valueOf(expSep)); if (expStartIdx > -1) { int expIdx = expStartIdx + expSep.length; boolean neg = false; if (str.charAt(expIdx) == opts.getMinusSign()) { ++expIdx; neg = true; } final String expStr = str.substring(expIdx); final int val = Integer.parseInt(expStr); return neg ? -val : val; } return 0; } @Test void testFrom() { // act/assert checkFrom(0.0, "0", 0); checkFrom(1.0, "1", 0); checkFrom(10.0, "1", 1); checkFrom(100.0, "1", 2); checkFrom(1000.0, "1", 3); checkFrom(10000.0, "1", 4); checkFrom(0.1, "1", -1); checkFrom(0.01, "1", -2); checkFrom(0.001, "1", -3); checkFrom(0.0001, "1", -4); checkFrom(0.00001, "1", -5); checkFrom(1.2, "12", -1); checkFrom(0.00971, "971", -5); checkFrom(56300, "563", 2); checkFrom(123.0, "123", 0); checkFrom(1230.0, "123", 1); checkFrom(12300.0, "123", 2); checkFrom(123000.0, "123", 3); checkFrom(12.3, "123", -1); checkFrom(1.23, "123", -2); checkFrom(0.123, "123", -3); checkFrom(0.0123, "123", -4); checkFrom(1.987654321e270, "1987654321", 261); checkFrom(1.987654321e-270, "1987654321", -279); checkFrom(Math.PI, "3141592653589793", -15); checkFrom(Math.E, "2718281828459045", -15); checkFrom(Double.MAX_VALUE, "17976931348623157", 292); checkFrom(Double.MIN_VALUE, "49", -325); checkFrom(Double.MIN_NORMAL, "22250738585072014", -324); } @Test void testFromNotFinite() { // arrange final String msg = "Double is not finite"; // act/assert assertThrowsWithMessage(() -> ParsedDecimal.from(Double.NaN), IllegalArgumentException.class, msg); assertThrowsWithMessage(() -> ParsedDecimal.from(Double.NEGATIVE_INFINITY), IllegalArgumentException.class, msg); assertThrowsWithMessage(() -> ParsedDecimal.from(Double.POSITIVE_INFINITY), IllegalArgumentException.class, msg); } @Test void testIsZero() { // act/assert Assertions.assertTrue(ParsedDecimal.from(0.0).isZero()); Assertions.assertTrue(ParsedDecimal.from(-0.0).isZero()); Assertions.assertFalse(ParsedDecimal.from(1.0).isZero()); Assertions.assertFalse(ParsedDecimal.from(-1.0).isZero()); Assertions.assertFalse(ParsedDecimal.from(Double.MIN_NORMAL).isZero()); Assertions.assertFalse(ParsedDecimal.from(-Double.MIN_NORMAL).isZero()); Assertions.assertFalse(ParsedDecimal.from(Double.MAX_VALUE).isZero()); Assertions.assertFalse(ParsedDecimal.from(-Double.MIN_VALUE).isZero()); } @Test void testMaxPrecision() { // arrange final double d = 1.02576552; // act assertMaxPrecision(d, 10, false, "102576552", -8); assertMaxPrecision(d, 9, false, "102576552", -8); assertMaxPrecision(d, 8, false, "10257655", -7); assertMaxPrecision(d, 7, false, "1025766", -6); assertMaxPrecision(d, 6, false, "102577", -5); assertMaxPrecision(d, 5, false, "10258", -4); assertMaxPrecision(d, 4, false, "1026", -3); assertMaxPrecision(d, 3, false, "103", -2); assertMaxPrecision(d, 2, false, "1", 0); assertMaxPrecision(d, 1, false, "1", 0); assertMaxPrecision(d, 0, false, "102576552", -8); } @Test void testMaxPrecision_carry() { // arrange final double d = -999.0999e50; // act assertMaxPrecision(d, 8, true, "9990999", 46); assertMaxPrecision(d, 7, true, "9990999", 46); assertMaxPrecision(d, 6, true, "9991", 49); assertMaxPrecision(d, 5, true, "9991", 49); assertMaxPrecision(d, 4, true, "9991", 49); assertMaxPrecision(d, 3, true, "999", 50); assertMaxPrecision(d, 2, true, "1", 53); assertMaxPrecision(d, 1, true, "1", 53); assertMaxPrecision(d, 0, true, "9990999", 46); } @Test void testMaxPrecision_halfEvenRounding() { // act/assert // Test values taken from RoundingMode.HALF_EVEN javadocs assertMaxPrecision(5.5, 1, false, "6", 0); assertMaxPrecision(2.5, 1, false, "2", 0); assertMaxPrecision(1.6, 1, false, "2", 0); assertMaxPrecision(1.1, 1, false, "1", 0); assertMaxPrecision(1.0, 1, false, "1", 0); assertMaxPrecision(-1.0, 1, true, "1", 0); assertMaxPrecision(-1.1, 1, true, "1", 0); assertMaxPrecision(-1.6, 1, true, "2", 0); assertMaxPrecision(-2.5, 1, true, "2", 0); assertMaxPrecision(-5.5, 1, true, "6", 0); } @Test void testMaxPrecision_random() { // arrange final UniformRandomProvider rand = RandomSource.XO_RO_SHI_RO_128_PP.create(0L); final ParsedDecimal.FormatOptions opts = new FormatOptionsImpl(); for (int i = 0; i < 10_000; ++i) { final double d = createRandomDouble(rand); final int precision = rand.nextInt(20) + 1; final MathContext ctx = new MathContext(precision, RoundingMode.HALF_EVEN); final ParsedDecimal dec = ParsedDecimal.from(d); // act dec.maxPrecision(precision); // assert Assertions.assertEquals(new BigDecimal(Double.toString(d), ctx).doubleValue(), Double.parseDouble(dec.toScientificString(opts))); } } @Test void testMaxPrecision_singleDigits() { // act assertMaxPrecision(9.0, 1, false, "9", 0); assertMaxPrecision(1.0, 1, false, "1", 0); assertMaxPrecision(0.0, 1, false, "0", 0); assertMaxPrecision(-0.0, 1, true, "0", 0); assertMaxPrecision(-1.0, 1, true, "1", 0); assertMaxPrecision(-9.0, 1, true, "9", 0); } @Test void testRound_mixed() { // arrange final double a = 9.94e-10; final double b = -3.1415; final double c = 5.55e10; // act/assert assertRound(a, -13, false, "994", -12); assertRound(a, -12, false, "994", -12); assertRound(a, -11, false, "99", -11); assertRound(a, -10, false, "1", -9); assertRound(a, -9, false, "1", -9); assertRound(a, -8, false, "0", 0); assertRound(b, -5, true, "31415", -4); assertRound(b, -4, true, "31415", -4); assertRound(b, -3, true, "3142", -3); assertRound(b, -2, true, "314", -2); assertRound(b, -1, true, "31", -1); assertRound(b, 0, true, "3", 0); assertRound(b, 1, true, "0", 0); assertRound(b, 2, true, "0", 0); assertRound(c, 7, false, "555", 8); assertRound(c, 8, false, "555", 8); assertRound(c, 9, false, "56", 9); assertRound(c, 10, false, "6", 10); assertRound(c, 11, false, "1", 11); assertRound(c, 12, false, "0", 0); } @Test void testRound_nine() { // arrange final double a = 9e-10; final double b = -9; final double c = 9e10; // act/assert assertRound(a, -11, false, "9", -10); assertRound(a, -10, false, "9", -10); assertRound(a, -9, false, "1", -9); assertRound(b, -1, true, "9", 0); assertRound(b, 0, true, "9", 0); assertRound(b, 1, true, "1", 1); assertRound(c, 9, false, "9", 10); assertRound(c, 10, false, "9", 10); assertRound(c, 11, false, "1", 11); } @Test void testRound_one() { // arrange final double a = 1e-10; final double b = -1; final double c = 1e10; // act/assert assertRound(a, -11, false, "1", -10); assertRound(a, -10, false, "1", -10); assertRound(a, -9, false, "0", 0); assertRound(b, -1, true, "1", 0); assertRound(b, 0, true, "1", 0); assertRound(b, 1, true, "0", 0); assertRound(c, 9, false, "1", 10); assertRound(c, 10, false, "1", 10); assertRound(c, 11, false, "0", 0); } @Test void testStringMethodAccuracy_random() { // arrange final UniformRandomProvider rand = RandomSource.XO_RO_SHI_RO_128_PP.create(0L); final FormatOptionsImpl stdOpts = new FormatOptionsImpl(); final FormatOptionsImpl altOpts = new FormatOptionsImpl(); altOpts.setExponentSeparator("e"); altOpts.setIncludeFractionPlaceholder(false); double d; for (int i = 0; i < 10_000; ++i) { d = createRandomDouble(rand); // act/assert Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toScientificString(stdOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toScientificString(altOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toEngineeringString(stdOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toEngineeringString(altOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toPlainString(stdOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toPlainString(altOpts))); } } @Test void testStringMethodAccuracy_sequence() { // arrange final double min = -1000; final double max = 1000; final double delta = 0.1; final FormatOptionsImpl stdOpts = new FormatOptionsImpl(); final FormatOptionsImpl altOpts = new FormatOptionsImpl(); altOpts.setExponentSeparator("e"); altOpts.setIncludeFractionPlaceholder(false); Assertions.assertEquals(10.0, Double.parseDouble(ParsedDecimal.from(10.0).toScientificString(stdOpts))); for (double d = min; d <= max; d += delta) { // act/assert Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toScientificString(stdOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toScientificString(altOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toEngineeringString(stdOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toEngineeringString(altOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toPlainString(stdOpts))); Assertions.assertEquals(d, Double.parseDouble(ParsedDecimal.from(d).toPlainString(altOpts))); } } @Test void testStringMethods_customDigits() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); opts.setDigitsFromString("abcdefghij"); // act/assert Assertions.assertEquals("b.a", ParsedDecimal.from(1.0).toPlainString(opts)); Assertions.assertEquals("-a.abcd", ParsedDecimal.from(-0.0123).toPlainString(opts)); Assertions.assertEquals("bc.de", ParsedDecimal.from(12.34).toPlainString(opts)); Assertions.assertEquals("baaaa.a", ParsedDecimal.from(10000).toPlainString(opts)); Assertions.assertEquals("jihgfedcba.a", ParsedDecimal.from(9876543210d).toPlainString(opts)); Assertions.assertEquals("b.a", ParsedDecimal.from(1.0).toScientificString(opts)); Assertions.assertEquals("-b.cdE-c", ParsedDecimal.from(-0.0123).toScientificString(opts)); Assertions.assertEquals("b.cdeEb", ParsedDecimal.from(12.34).toScientificString(opts)); Assertions.assertEquals("b.aEe", ParsedDecimal.from(10000).toScientificString(opts)); Assertions.assertEquals("j.ihgfedcbEj", ParsedDecimal.from(9876543210d).toScientificString(opts)); Assertions.assertEquals("b.a", ParsedDecimal.from(1.0).toEngineeringString(opts)); Assertions.assertEquals("-bc.dE-d", ParsedDecimal.from(-0.0123).toEngineeringString(opts)); Assertions.assertEquals("bc.de", ParsedDecimal.from(12.34).toEngineeringString(opts)); Assertions.assertEquals("ba.aEd", ParsedDecimal.from(10000).toEngineeringString(opts)); Assertions.assertEquals("j.ihgfedcbEj", ParsedDecimal.from(9876543210d).toEngineeringString(opts)); } @Test void testToEngineeringString_altFormat() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); opts.setIncludeFractionPlaceholder(false); opts.setSignedZero(false); opts.setDecimalSeparator(','); opts.setMinusSign('!'); opts.setExponentSeparator("x10^"); opts.setAlwaysIncludeExponent(true); // act/assert checkToEngineeringString(0.0, "0x10^0", opts); checkToEngineeringString(-0.0, "0x10^0", opts); checkToEngineeringString(1.0, "1x10^0", opts); checkToEngineeringString(1.5, "1,5x10^0", opts); checkToEngineeringString(10, "10x10^0", opts); checkToEngineeringString(-0.000000123, "!123x10^!9", opts); checkToEngineeringString(12300000, "12,3x10^6", opts); checkToEngineeringString(Math.PI, "3,141592653589793x10^0", opts); checkToEngineeringString(Math.E, "2,718281828459045x10^0", opts); checkToEngineeringString(-Double.MAX_VALUE, "!179,76931348623157x10^306", opts); checkToEngineeringString(Double.MIN_VALUE, "4,9x10^!324", opts); checkToEngineeringString(Double.MIN_NORMAL, "22,250738585072014x10^!309", opts); } @Test void testToEngineeringString_defaults() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); // act/assert checkToEngineeringString(0.0, "0.0", opts); checkToEngineeringString(-0.0, "-0.0", opts); checkToEngineeringString(1.0, "1.0", opts); checkToEngineeringString(1.5, "1.5", opts); checkToEngineeringString(10, "10.0", opts); checkToEngineeringString(-0.000000123, "-123.0E-9", opts); checkToEngineeringString(12300000, "12.3E6", opts); checkToEngineeringString(Math.PI, "3.141592653589793", opts); checkToEngineeringString(Math.E, "2.718281828459045", opts); checkToEngineeringString(-Double.MAX_VALUE, "-179.76931348623157E306", opts); checkToEngineeringString(Double.MIN_VALUE, "4.9E-324", opts); checkToEngineeringString(Double.MIN_NORMAL, "22.250738585072014E-309", opts); } @Test void testToPlainString_altFormat() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); opts.setIncludeFractionPlaceholder(false); opts.setSignedZero(false); opts.setDecimalSeparator(','); opts.setMinusSign('!'); opts.setThousandsGroupingSeparator('_'); opts.setGroupThousands(true); // act/assert checkToPlainString(0.0, "0", opts); checkToPlainString(-0.0, "0", opts); checkToPlainString(1.0, "1", opts); checkToPlainString(1.5, "1,5", opts); checkToPlainString(12, "12", opts); checkToPlainString(123, "123", opts); checkToPlainString(1234, "1_234", opts); checkToPlainString(12345, "12_345", opts); checkToPlainString(123456, "123_456", opts); checkToPlainString(1234567, "1_234_567", opts); checkToPlainString(12345678, "12_345_678", opts); checkToPlainString(123456789, "123_456_789", opts); checkToPlainString(1234567890, "1_234_567_890", opts); checkToPlainString(-0.000123, "!0,000123", opts); checkToPlainString(12301, "12_301", opts); checkToPlainString(Math.PI, "3,141592653589793", opts); checkToPlainString(Math.E, "2,718281828459045", opts); checkToPlainString(-12345.6789, "!12_345,6789", opts); checkToPlainString(1.23e12, "1_230_000_000_000", opts); checkToPlainString(1.23e-12, "0,00000000000123", opts); } @Test void testToPlainString_defaults() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); // act/assert checkToPlainString(0.0, "0.0", opts); checkToPlainString(-0.0, "-0.0", opts); checkToPlainString(1.0, "1.0", opts); checkToPlainString(1.5, "1.5", opts); checkToPlainString(12, "12.0", opts); checkToPlainString(123, "123.0", opts); checkToPlainString(1234, "1234.0", opts); checkToPlainString(12345, "12345.0", opts); checkToPlainString(123456, "123456.0", opts); checkToPlainString(1234567, "1234567.0", opts); checkToPlainString(12345678, "12345678.0", opts); checkToPlainString(123456789, "123456789.0", opts); checkToPlainString(1234567890, "1234567890.0", opts); checkToPlainString(-0.000123, "-0.000123", opts); checkToPlainString(12301, "12301.0", opts); checkToPlainString(Math.PI, "3.141592653589793", opts); checkToPlainString(Math.E, "2.718281828459045", opts); checkToPlainString(-12345.6789, "-12345.6789", opts); checkToPlainString(1.23e12, "1230000000000.0", opts); checkToPlainString(1.23e-12, "0.00000000000123", opts); } @Test void testToScientificString_altFormats() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); opts.setIncludeFractionPlaceholder(false); opts.setSignedZero(false); opts.setDecimalSeparator(','); opts.setMinusSign('!'); opts.setExponentSeparator("x10^"); opts.setAlwaysIncludeExponent(true); // act/assert checkToScientificString(0.0, "0x10^0", opts); checkToScientificString(-0.0, "0x10^0", opts); checkToScientificString(1.0, "1x10^0", opts); checkToScientificString(1.5, "1,5x10^0", opts); checkToScientificString(-0.000123, "!1,23x10^!4", opts); checkToScientificString(12301, "1,2301x10^4", opts); checkToScientificString(Math.PI, "3,141592653589793x10^0", opts); checkToScientificString(Math.E, "2,718281828459045x10^0", opts); checkToScientificString(-Double.MAX_VALUE, "!1,7976931348623157x10^308", opts); checkToScientificString(Double.MIN_VALUE, "4,9x10^!324", opts); checkToScientificString(Double.MIN_NORMAL, "2,2250738585072014x10^!308", opts); } @Test void testToScientificString_defaults() { // arrange final FormatOptionsImpl opts = new FormatOptionsImpl(); // act/assert checkToScientificString(0.0, "0.0", opts); checkToScientificString(-0.0, "-0.0", opts); checkToScientificString(1.0, "1.0", opts); checkToScientificString(1.5, "1.5", opts); checkToScientificString(-0.000123, "-1.23E-4", opts); checkToScientificString(12301, "1.2301E4", opts); checkToScientificString(Math.PI, "3.141592653589793", opts); checkToScientificString(Math.E, "2.718281828459045", opts); checkToScientificString(-Double.MAX_VALUE, "-1.7976931348623157E308", opts); checkToScientificString(Double.MIN_VALUE, "4.9E-324", opts); checkToScientificString(Double.MIN_NORMAL, "2.2250738585072014E-308", opts); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/000077500000000000000000000000001511432740600307755ustar00rootroot00000000000000CosineDistanceTest.java000066400000000000000000000044701511432740600353210ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import java.math.BigDecimal; import java.math.RoundingMode; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; /** * Tests {@link CosineSimilarity}. */ class CosineDistanceTest { /** * Cosine distance under test. */ private static CosineDistance cosineDistance; /** * Creates the cosine distance object used throughout the tests. */ @BeforeAll public static void setUp() { cosineDistance = new CosineDistance(); } /** * Rounds up a value. * * @param value a value * @return rounded up value */ private Double roundValue(final Double value) { return new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).doubleValue(); } /** * Tests the cosine distance with several inputs. */ @Test void testCosineDistance() { assertEquals(Double.valueOf(0.5d), roundValue(cosineDistance.apply("the house", "da house"))); assertEquals(Double.valueOf(0.0d), roundValue(cosineDistance.apply("AB", "AB"))); assertEquals(Double.valueOf(1.0d), roundValue(cosineDistance.apply("AB", "BA"))); assertEquals(Double.valueOf(0.08d), roundValue(cosineDistance.apply( "the boy was from tamana shi, kumamoto ken, and the girl was from rio de janeiro, rio", "the boy was from tamana shi, kumamoto, and the boy was from rio de janeiro, rio de janeiro"))); } } CosineSimilarityTest.java000066400000000000000000000040701511432740600357110ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; class CosineSimilarityTest { @Test void testCosineSimilarityReturningDoubleWhereByteValueIsZero() { final Map hashMap = new HashMap<>(); assertEquals(0.0, CosineSimilarity.INSTANCE.cosineSimilarity(hashMap, hashMap), 0.01); } @Test void testCosineSimilarityThrowsIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> CosineSimilarity.INSTANCE.cosineSimilarity(new HashMap<>(), null)); } @Test void testCosineSimilarityWithNonEmptyMap() { final Map hashMap = new HashMap<>(); final Integer integer = -397; hashMap.put("3J/$3.L", integer); final Map hashMapTwo = new HashMap<>(); assertEquals(0.0, CosineSimilarity.INSTANCE.cosineSimilarity(hashMap, hashMapTwo), 0.01); } @Test void testCosineSimilarityWithNull() { assertThrows(IllegalArgumentException.class, () -> CosineSimilarity.INSTANCE.cosineSimilarity(null, null)); } } DamerauLevenshteinDistanceTest.java000066400000000000000000000267621511432740600376740ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Arrays; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link DamerauLevenshteinDistance}. */ public class DamerauLevenshteinDistanceTest { private static DamerauLevenshteinDistance defaultInstance; @BeforeAll static void createInstance() { defaultInstance = new DamerauLevenshteinDistance(); } static Stream limitedDamerauLevenshteinDistanceTestCases() { return Stream.of( Arguments.of("", "test", 10, 4), Arguments.of("test", "", 10, 4), Arguments.of("", "test", 2, -1), Arguments.of("test", "", 2, -1), Arguments.of("testing long string", "testing", 2, -1), Arguments.of("kitten", "sitting", 1, -1), Arguments.of("saturday", "sunday", 3, 3), Arguments.of("hello", "world", 6, 4), Arguments.of("algorithm", "logarithm", 1, -1), Arguments.of("computer", "comptuer", 1, 1), Arguments.of("receive", "recieve", 3, 1), Arguments.of("programming", "porgramming", 0, -1), Arguments.of("test", "tset", 1, 1), Arguments.of("example", "exmaple", 3, 1), Arguments.of("transform", "transfrom", 0, -1), Arguments.of("information", "infromation", 1, 1), Arguments.of("development", "developemnt", 3, 1), Arguments.of("password", "passwrod", 0, -1), Arguments.of("separate", "seperate", 1, 1), Arguments.of("definitely", "definately", 3, 1), Arguments.of("occurrence", "occurence", 0, -1), Arguments.of("necessary", "neccessary", 1, 1), Arguments.of("restaurant", "restaraunt", 4, 2), Arguments.of("beginning", "begining", 0, -1), Arguments.of("government", "goverment", 1, 1), Arguments.of("abcdefghijklmnop", "ponmlkjihgfedcba", 17, 15), Arguments.of("AAAAAAAAAA", "BBBBBBBBBB", 5, -1), Arguments.of("abababababab", "babababababa", 2, 2), Arguments.of("supercalifragilisticexpialidocious", "supercalifragilisticexpialidocous", 3, 1), Arguments.of("pneumonoultramicroscopicsilicovolcanoconiosiss", "pneumonoultramicroscopicsilicovolcanoconiosis", 0, -1), Arguments.of("abcdefg", "gfedcba", 6, 6), Arguments.of("xyxyxyxyxy", "yxyxyxyxyx", 4, 2), Arguments.of("aaaaabbbbbccccc", "cccccbbbbbaaaaa", 5, -1), Arguments.of("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsovrethelazydog", 1, 1), Arguments.of("antidisestablishmentarianism", "antidisestablishmentarianisn", 3, 1) ); } static Stream limitedDamerauLevenshteinDistanceTestCases_SimilarityInput() { return SimilarityInputTest.similarityInputs() .flatMap(cls -> limitedDamerauLevenshteinDistanceTestCases().map(arguments -> { final Object[] values = Arrays.copyOf(arguments.get(), arguments.get().length + 1); values[values.length - 1] = cls; return Arguments.of(values); })); } static Stream unlimitedDamerauLevenshteinDistanceTestCases() { return Stream.of( Arguments.of("", "test", 4), Arguments.of("test", "", 4), Arguments.of("kitten", "sitting", 3), Arguments.of("saturday", "sunday", 3), Arguments.of("hello", "world", 4), Arguments.of("algorithm", "logarithm", 3), Arguments.of("computer", "comptuer", 1), Arguments.of("receive", "recieve", 1), Arguments.of("programming", "porgramming", 1), Arguments.of("test", "tset", 1), Arguments.of("example", "exmaple", 1), Arguments.of("transform", "transfrom", 1), Arguments.of("information", "infromation", 1), Arguments.of("development", "developemnt", 1), Arguments.of("password", "passwrod", 1), Arguments.of("separate", "seperate", 1), Arguments.of("definitely", "definately", 1), Arguments.of("occurrence", "occurence", 1), Arguments.of("necessary", "neccessary", 1), Arguments.of("restaurant", "restaraunt", 2), Arguments.of("beginning", "begining", 1), Arguments.of("government", "goverment", 1), Arguments.of("abcdefghijklmnop", "ponmlkjihgfedcba", 15), Arguments.of("AAAAAAAAAA", "BBBBBBBBBB", 10), Arguments.of("abababababab", "babababababa", 2), Arguments.of("supercalifragilisticexpialidocious", "supercalifragilisticexpialidocous", 1), Arguments.of("pneumonoultramicroscopicsilicovolcanoconiosiss", "pneumonoultramicroscopicsilicovolcanoconiosis", 1), Arguments.of("abcdefg", "gfedcba", 6), Arguments.of("xyxyxyxyxy", "yxyxyxyxyx", 2), Arguments.of("aaaaabbbbbccccc", "cccccbbbbbaaaaa", 10), Arguments.of("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsovrethelazydog", 1), Arguments.of("antidisestablishmentarianism", "antidisestablishmentarianisn", 1) ); } static Stream unlimitedDamerauLevenshteinDistanceTestCases_SimilarityInput() { return SimilarityInputTest.similarityInputs() .flatMap(cls -> unlimitedDamerauLevenshteinDistanceTestCases().map(arguments -> { final Object[] values = Arrays.copyOf(arguments.get(), arguments.get().length + 1); values[values.length - 1] = cls; return Arguments.of(values); })); } @ParameterizedTest(name = "DamerauLevenshteinDistance.unlimitedCompare(\"{0}\", \"{1}\") should return {2}") @MethodSource("unlimitedDamerauLevenshteinDistanceTestCases") void testCalculateDamerauLevenshteinDistance(final String left, final String right, final int expectedDistance) { final int leftRightDistance = defaultInstance.apply(left, right); final int rightLeftDistance = defaultInstance.apply(right, left); assertEquals(expectedDistance, leftRightDistance); assertEquals(expectedDistance, rightLeftDistance); } @ParameterizedTest(name = "DamerauLevenshteinDistance.limitedCompare(\"{0}\", \"{1}\") should return {2}") @MethodSource("limitedDamerauLevenshteinDistanceTestCases") void testCalculateDamerauLevenshteinDistance(final String left, final String right, final int threshold, final int expectedDistance) { final DamerauLevenshteinDistance instance = new DamerauLevenshteinDistance(threshold); final int leftRightDistance = instance.apply(left, right); final int rightLeftDistance = instance.apply(right, left); assertEquals(expectedDistance, leftRightDistance); assertEquals(expectedDistance, rightLeftDistance); } @ParameterizedTest(name = "DamerauLevenshteinDistance.unlimitedCompare(\"{0}\", \"{1}\") should return {2} ({3})") @MethodSource("unlimitedDamerauLevenshteinDistanceTestCases_SimilarityInput") void testCalculateDamerauLevenshteinDistance_SimilarityInput(final String left, final String right, final int expectedDistance, final Class cls) { final SimilarityInput leftInput = SimilarityInputTest.build(cls, left); final SimilarityInput rightInput = SimilarityInputTest.build(cls, right); final int leftRightDistance = defaultInstance.apply(leftInput, rightInput); final int rightLeftDistance = defaultInstance.apply(rightInput, leftInput); assertEquals(expectedDistance, leftRightDistance); assertEquals(expectedDistance, rightLeftDistance); } @ParameterizedTest(name = "DamerauLevenshteinDistance.limitedCompare(\"{0}\", \"{1}\") should return {2}") @MethodSource("limitedDamerauLevenshteinDistanceTestCases_SimilarityInput") void testCalculateDamerauLevenshteinDistance_SimilarityInput(final String left, final String right, final int threshold, final int expectedDistance, final Class cls) { final DamerauLevenshteinDistance instance = new DamerauLevenshteinDistance(threshold); final SimilarityInput leftInput = SimilarityInputTest.build(cls, left); final SimilarityInput rightInput = SimilarityInputTest.build(cls, right); final int leftRightDistance = instance.apply(leftInput, rightInput); final int rightLeftDistance = instance.apply(rightInput, leftInput); assertEquals(expectedDistance, leftRightDistance); assertEquals(expectedDistance, rightLeftDistance); } @Test void testGetThresholdDirectlyAfterObjectInstantiation() { assertNull(defaultInstance.getThreshold()); } @Test void testGetThresholdIsCorrect() { final DamerauLevenshteinDistance distance = new DamerauLevenshteinDistance(10); assertEquals(10, distance.getThreshold()); } @Test void testInvalidThresholdThrows() { assertThrows(IllegalArgumentException.class, () -> new DamerauLevenshteinDistance(-1)); } @Test void testNullInputsThrowLimited() { final DamerauLevenshteinDistance instance = new DamerauLevenshteinDistance(10); assertThrows(IllegalArgumentException.class, () -> instance.apply(null, "test")); assertThrows(IllegalArgumentException.class, () -> instance.apply("test", null)); assertThrows(IllegalArgumentException.class, () -> instance.apply(null, SimilarityInput.input("test"))); assertThrows(IllegalArgumentException.class, () -> instance.apply(SimilarityInput.input("test"), null)); } @Test void testNullInputsThrowUnlimited() { assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply(null, "test")); assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply("test", null)); assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply(null, SimilarityInput.input("test"))); assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply(SimilarityInput.input("test"), null)); } } EditDistanceFromTest.java000066400000000000000000000031361511432740600356100ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class EditDistanceFromTest { private LongestCommonSubsequenceDistance longestCommonSubsequenceDistance; private EditDistanceFrom editDistanceFrom; @BeforeEach void doBeforeEachTest() { longestCommonSubsequenceDistance = new LongestCommonSubsequenceDistance(); editDistanceFrom = new EditDistanceFrom<>(longestCommonSubsequenceDistance, "asdf"); } @Test void testGetLeft() { assertEquals("asdf", editDistanceFrom.getLeft()); } @Test void testGetSimilarityScore() { assertEquals(longestCommonSubsequenceDistance, editDistanceFrom.getEditDistance()); } } FuzzyScoreTest.java000066400000000000000000000051521511432740600345470ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Locale; import org.junit.jupiter.api.Test; /** * Tests {@link FuzzyScore}. */ class FuzzyScoreTest { private static final FuzzyScore ENGLISH_SCORE = new FuzzyScore(Locale.ENGLISH); @Test void testGetFuzzyScore() { assertEquals(0, ENGLISH_SCORE.fuzzyScore("", "")); assertEquals(0, ENGLISH_SCORE.fuzzyScore("Workshop", "b")); assertEquals(1, ENGLISH_SCORE.fuzzyScore("Room", "o")); assertEquals(1, ENGLISH_SCORE.fuzzyScore("Workshop", "w")); assertEquals(2, ENGLISH_SCORE.fuzzyScore("Workshop", "ws")); assertEquals(4, ENGLISH_SCORE.fuzzyScore("Workshop", "wo")); assertEquals(3, ENGLISH_SCORE.fuzzyScore("Apache Software Foundation", "asf")); } @Test void testGetFuzzyScore_NullNullLocale() { assertThrows(IllegalArgumentException.class, () -> ENGLISH_SCORE.fuzzyScore(null, null)); } @Test void testGetFuzzyScore_NullStringLocale() { assertThrows(IllegalArgumentException.class, () -> ENGLISH_SCORE.fuzzyScore(null, "not null")); } @Test void testGetFuzzyScore_StringNullLocale() { assertThrows(IllegalArgumentException.class, () -> ENGLISH_SCORE.fuzzyScore("not null", null)); } @Test void testGetLocale() { final Locale locale = Locale.CANADA_FRENCH; final FuzzyScore fuzzyScore = new FuzzyScore(locale); final Locale localeTwo = fuzzyScore.getLocale(); assertSame(localeTwo, locale); } @Test void testMissingLocale() { assertThrows(IllegalArgumentException.class, () -> new FuzzyScore((Locale) null)); } } HammingDistanceTest.java000066400000000000000000000075571511432740600354720ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link HammingDistance}. */ class HammingDistanceTest { private static HammingDistance distance; @BeforeAll public static void setUp() { distance = new HammingDistance(); } @Test void testApply_DifferentSimilarityInputLength() { assertThrows(IllegalArgumentException.class, () -> distance.apply(new SimilarityCharacterInput("a"), new SimilarityCharacterInput("ab"))); } @Test void testApply_NullSimilarityInput() { assertThrows(IllegalArgumentException.class, () -> distance.apply(null, new SimilarityCharacterInput("a"))); } @Test void testApply_SimilarityInputNull() { assertThrows(IllegalArgumentException.class, () -> distance.apply(new SimilarityCharacterInput("a"), null)); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testHammingDistance(final Class cls) { assertEquals(0, distance.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, ""))); assertEquals(0, distance.apply(SimilarityInputTest.build(cls, "pappa"), SimilarityInputTest.build(cls, "pappa"))); assertEquals(1, distance.apply(SimilarityInputTest.build(cls, "papaa"), SimilarityInputTest.build(cls, "pappa"))); assertEquals(3, distance.apply(SimilarityInputTest.build(cls, "karolin"), SimilarityInputTest.build(cls, "kathrin"))); assertEquals(3, distance.apply(SimilarityInputTest.build(cls, "karolin"), SimilarityInputTest.build(cls, "kerstin"))); assertEquals(2, distance.apply(SimilarityInputTest.build(cls, "1011101"), SimilarityInputTest.build(cls, "1001001"))); assertEquals(3, distance.apply(SimilarityInputTest.build(cls, "2173896"), SimilarityInputTest.build(cls, "2233796"))); assertEquals(2, distance.apply(SimilarityInputTest.build(cls, "ATCG"), SimilarityInputTest.build(cls, "ACCC"))); } @Test void testHammingDistance_nullLeftValue() { assertThrows(IllegalArgumentException.class, () -> distance.apply(null, "")); } @Test void testHammingDistance_nullRightValue() { assertThrows(IllegalArgumentException.class, () -> distance.apply("", null)); } @Test void testHammingDistanceCharSequence() { assertEquals(0, distance.apply("", "")); assertEquals(0, distance.apply("pappa", "pappa")); assertEquals(1, distance.apply("papaa", "pappa")); assertEquals(3, distance.apply("karolin", "kathrin")); assertEquals(3, distance.apply("karolin", "kerstin")); assertEquals(2, distance.apply("1011101", "1001001")); assertEquals(3, distance.apply("2173896", "2233796")); assertEquals(2, distance.apply("ATCG", "ACCC")); } } IntersectionResultTest.java000066400000000000000000000131011511432740600362620ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import java.util.HashMap; import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Tests {@link IntersectionResult}. */ class IntersectionResultTest { @Test void testEquals() { final IntersectionResult[] results = { new IntersectionResult(0, 0, 0), new IntersectionResult(10, 0, 0), new IntersectionResult(10, 10, 0), new IntersectionResult(10, 10, 10), }; // Test a different instance with same values Assertions.assertEquals(results[0], new IntersectionResult(0, 0, 0)); final Object something = new Object(); for (int i = 0; i < results.length; i++) { Assertions.assertNotEquals(results[i], something); Assertions.assertNotEquals(null, results[i]); for (int j = 0; j < results.length; j++) { Assertions.assertEquals(results[i].equals(results[j]), i == j); } } } @Test void testHashCode() { final IntersectionResult[] results = { new IntersectionResult(10, 0, 0), new IntersectionResult(10, 10, 0), new IntersectionResult(10, 10, 10), }; final HashMap map = new HashMap<>(); final int offset = 123; for (int i = 0; i < results.length; i++) { map.put(results[i], i + offset); } for (int i = 0; i < results.length; i++) { Assertions.assertEquals(i + offset, map.get(results[i])); } } @Test void testNewIntersectionResult_WithIntersectionAboveSizeAorB() { final int sizeA = 1; final int sizeB = 2; final int intersection = Math.max(sizeA, sizeB) + 1; Assertions.assertThrows(IllegalArgumentException.class, () -> new IntersectionResult(sizeA, sizeB, intersection)); Assertions.assertThrows(IllegalArgumentException.class, () -> new IntersectionResult(sizeB, sizeA, intersection)); } @Test void testNewIntersectionResult_WithNegativeIntersection() { final int sizeA = 0; final int sizeB = 0; final int intersection = -1; Assertions.assertThrows(IllegalArgumentException.class, () -> new IntersectionResult(sizeA, sizeB, intersection)); } @Test void testNewIntersectionResult_WithNegativeSizeA() { final int sizeA = -1; final int sizeB = 0; final int intersection = 0; Assertions.assertThrows(IllegalArgumentException.class, () -> new IntersectionResult(sizeA, sizeB, intersection)); } @Test void testNewIntersectionResult_WithNegativeSizeB() { final int sizeA = 0; final int sizeB = -1; final int intersection = 0; Assertions.assertThrows(IllegalArgumentException.class, () -> new IntersectionResult(sizeA, sizeB, intersection)); } @Test void testNewIntersectionResult_WithZeros() { final int sizeA = 0; final int sizeB = 0; final int intersection = 0; new IntersectionResult(sizeA, sizeB, intersection); } @Test void testProperties() { final ThreadLocalRandom rand = ThreadLocalRandom.current(); final int max = 1024; for (int i = 0; i < 5; i++) { // Ensure the min is above 0 final int sizeA = rand.nextInt(max) + 1; final int sizeB = rand.nextInt(max) + 1; final int intersection = rand.nextInt(Math.min(sizeA, sizeB)); final IntersectionResult result = new IntersectionResult(sizeA, sizeB, intersection); Assertions.assertEquals(sizeA, result.getSizeA()); Assertions.assertEquals(sizeB, result.getSizeB()); Assertions.assertEquals(intersection, result.getIntersection()); } } @Test void testToString() { final ThreadLocalRandom rand = ThreadLocalRandom.current(); final int max = 9; for (int i = 0; i < 5; i++) { // Ensure the min is above 0 final int sizeA = rand.nextInt(max) + 1; final int sizeB = rand.nextInt(max) + 1; final int intersection = rand.nextInt(Math.min(sizeA, sizeB)); final IntersectionResult result = new IntersectionResult(sizeA, sizeB, intersection); final String string = result.toString(); // Not perfect as this will match substrings too. The chance of error // is limited by restricting the numbers to a max of 10. Assertions.assertTrue(string.contains(String.valueOf(sizeA))); Assertions.assertTrue(string.contains(String.valueOf(sizeB))); Assertions.assertTrue(string.contains(String.valueOf(intersection))); } } } IntersectionSimilarityTest.java000066400000000000000000000367261511432740600371540ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.regex.Pattern; import org.junit.jupiter.api.Test; /** * Tests {@link IntersectionSimilarity}. */ class IntersectionSimilarityTest { private static void assertIntersection(final IntersectionSimilarity similarity, final CharSequence cs1, final CharSequence cs2, final int sizeA, final int sizeB, final int intersection) { final IntersectionResult result = similarity.apply(cs1, cs2); assertEquals(sizeA, result.getSizeA(), "Size A error"); assertEquals(sizeB, result.getSizeB(), "Size B error"); assertEquals(intersection, result.getIntersection(), "Intersection error"); } /** * Convert the {@link CharSequence} to a {@link List} of bigrams (pairs of characters). These are represented using 2 16-bit chars packed into a 32-bit int. * * @param sequence the sequence * @return the list */ private static List toBigramList(final CharSequence sequence) { final int length = sequence.length(); final List list = new ArrayList<>(length); if (length > 1) { char ch2 = sequence.charAt(0); for (int i = 1; i < length; i++) { final char ch1 = ch2; ch2 = sequence.charAt(i); list.add(Integer.valueOf(ch1 << 16 | ch2)); } } return list; } /** * Convert the {@link CharSequence} to a {@link Set} of bigrams (pairs of characters). These are represented using 2 16-bit chars packed into a 32-bit int. * * @param sequence the sequence * @return the set */ private static Set toBigramSet(final CharSequence sequence) { final int length = sequence.length(); final Set set = new HashSet<>(length); if (length > 1) { char ch2 = sequence.charAt(0); for (int i = 1; i < length; i++) { final char ch1 = ch2; ch2 = sequence.charAt(i); set.add(Integer.valueOf(ch1 << 16 | ch2)); } } return set; } /** * Convert the {@link CharSequence} to a {@link List} of {@link Character}s. * * @param sequence the sequence * @return the list */ private static List toCharacterList(final CharSequence sequence) { final int length = sequence.length(); final List list = new ArrayList<>(length); for (int i = 0; i < length; i++) { list.add(sequence.charAt(i)); } return list; } /** * Convert the {@link CharSequence} to a {@link Set} of {@link Character}s. * * @param sequence the sequence * @return the set */ private static Set toCharacterSet(final CharSequence sequence) { final int length = sequence.length(); final Set set = new HashSet<>(length); for (int i = 0; i < length; i++) { set.add(sequence.charAt(i)); } return set; } private static int toF1ScorePercent(final IntersectionResult result) { final double value = 2.0 * result.getIntersection() / (result.getSizeA() + result.getSizeB()); // Convert to percentage return (int) Math.round(value * 100); } @Test void testApplyNullNull() { assertThrows(IllegalArgumentException.class, () -> new IntersectionSimilarity<>(cs -> new HashSet<>(Collections.singletonList(cs))).apply(null, null)); } @Test void testApplyNullString() { assertThrows(IllegalArgumentException.class, () -> new IntersectionSimilarity<>(cs -> new HashSet<>(Collections.singletonList(cs))).apply(null, "right")); } @Test void testApplyStringNull() { assertThrows(IllegalArgumentException.class, () -> new IntersectionSimilarity<>(cs -> new HashSet<>(Collections.singletonList(cs))).apply("left", null)); } @Test void testConstructorWithNullConverterThrows() { assertThrows(IllegalArgumentException.class, () -> new IntersectionSimilarity<>(null)); } @Test void testF1ScoreUsingListWordBigrams() { // Example of a word letter pairs algorithm by Simon White: // http://www.catalysoft.com/articles/StrikeAMatch.html // This splits into words using whitespace and then computes uppercase // bigrams for each word. // Split on whitespace final Pattern pattern = Pattern.compile("\\s+"); // Compute using pairs of characters (bigrams) for each word. // This can be done using a 32-bit int to store two 16-bit characters final Function> converter = cs -> { final List set = new ArrayList<>(); for (final String word : pattern.split(cs)) { if (word.length() > 1) { // The strings are converted to upper case char ch2 = Character.toUpperCase(word.charAt(0)); for (int i = 1; i < word.length(); i++) { final char ch1 = ch2; ch2 = Character.toUpperCase(word.charAt(i)); set.add(Integer.valueOf(ch1 << 16 | ch2)); } } } return set; }; final IntersectionSimilarity similarity = new IntersectionSimilarity<>(converter); String bookTitle; final String search1 = "Web Database Applications"; final String search2 = "PHP Web Applications"; final String search3 = "Web Aplications"; bookTitle = "Web Database Applications with PHP & MySQL"; assertEquals(82, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(68, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(59, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "Creating Database Web Applications with PHP and ASP"; assertEquals(71, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(59, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(50, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "Building Database Applications on the Web Using PHP3"; assertEquals(70, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(58, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(49, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "Building Web Database Applications with Visual Studio 6"; assertEquals(67, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(47, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(46, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "Web Application Development With PHP"; assertEquals(51, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(67, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(56, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "WebRAD: Building Database Applications on the Web with Visual FoxPro and Web Connection"; assertEquals(49, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(34, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(32, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "Structural Assessment: The Role of Large and Full-Scale Testing"; assertEquals(12, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(7, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(7, toF1ScorePercent(similarity.apply(bookTitle, search3))); bookTitle = "How to Find a Scholarship Online"; assertEquals(10, toF1ScorePercent(similarity.apply(bookTitle, search1))); assertEquals(11, toF1ScorePercent(similarity.apply(bookTitle, search2))); assertEquals(12, toF1ScorePercent(similarity.apply(bookTitle, search3))); } @Test void testIntersectionUsingListBigrams() { // Compute using pairs of characters (bigrams). // This can be done using a 32-bit int to store two 16-bit characters. // This test uses a list and so duplicates should be matched. final IntersectionSimilarity similarity = new IntersectionSimilarity<>(IntersectionSimilarityTest::toBigramList); // Expected: // size A or B = sequence length - 1 // intersection = count of matching bigrams (include duplicates) assertIntersection(similarity, "", "", 0, 0, 0); assertIntersection(similarity, "a", "", 0, 0, 0); assertIntersection(similarity, "a", "a", 0, 0, 0); assertIntersection(similarity, "a", "b", 0, 0, 0); assertIntersection(similarity, "aa", "ab", 1, 1, 0); assertIntersection(similarity, "ab", "ab", 1, 1, 1); assertIntersection(similarity, "aaba", "abaa", 3, 3, 3); assertIntersection(similarity, "aaaa", "aa", 3, 1, 1); assertIntersection(similarity, "aa", "aaaa", 1, 3, 1); assertIntersection(similarity, "aaaa", "aaa", 3, 2, 2); assertIntersection(similarity, "aabab", "ababa", 4, 4, 3); assertIntersection(similarity, "the same", "the same", 7, 7, 7); assertIntersection(similarity, "abcdefghijklm", "ab_defg ijklm", 12, 12, 8); } @Test void testIntersectionUsingListCharacter() { // Compute using single characters. // This test uses a list and so duplicates should be matched. final IntersectionSimilarity similarity = new IntersectionSimilarity<>(IntersectionSimilarityTest::toCharacterList); // Expected: // size A or B = sequence length // intersection = count of matching characters (include duplicates) assertIntersection(similarity, "", "", 0, 0, 0); assertIntersection(similarity, "a", "", 1, 0, 0); assertIntersection(similarity, "a", "a", 1, 1, 1); assertIntersection(similarity, "a", "b", 1, 1, 0); assertIntersection(similarity, "aa", "ab", 2, 2, 1); assertIntersection(similarity, "ab", "ab", 2, 2, 2); assertIntersection(similarity, "aaba", "abaa", 4, 4, 4); assertIntersection(similarity, "aaaa", "aa", 4, 2, 2); assertIntersection(similarity, "aa", "aaaa", 2, 4, 2); assertIntersection(similarity, "aaaa", "aaa", 4, 3, 3); assertIntersection(similarity, "aabab", "ababa", 5, 5, 5); assertIntersection(similarity, "the same", "the same", 8, 8, 8); assertIntersection(similarity, "abcdefghijklm", "ab_defg ijklm", 13, 13, 11); } @Test void testIntersectionUsingSetBigrams() { // Compute using pairs of characters (bigrams). // This can be done using a 32-bit int to store two 16-bit characters. // This test uses a set and so should not allow duplicates. final IntersectionSimilarity similarity = new IntersectionSimilarity<>(IntersectionSimilarityTest::toBigramSet); // Expected: // size A or B = count of unique bigrams (exclude duplicates) // intersection = count of unique matching bigrams (exclude duplicates) assertIntersection(similarity, "", "", 0, 0, 0); assertIntersection(similarity, "a", "", 0, 0, 0); assertIntersection(similarity, "a", "a", 0, 0, 0); assertIntersection(similarity, "a", "b", 0, 0, 0); assertIntersection(similarity, "aa", "ab", 1, 1, 0); assertIntersection(similarity, "ab", "ab", 1, 1, 1); assertIntersection(similarity, "aaba", "abaa", 3, 3, 3); assertIntersection(similarity, "aaaa", "aa", 1, 1, 1); assertIntersection(similarity, "aa", "aaaa", 1, 1, 1); assertIntersection(similarity, "aaaa", "aaa", 1, 1, 1); assertIntersection(similarity, "aabab", "ababa", 3, 2, 2); assertIntersection(similarity, "the same", "the same", 7, 7, 7); assertIntersection(similarity, "abcdefghijklm", "ab_defg ijklm", 12, 12, 8); } @Test void testIntersectionUsingSetCharacter() { // Compute using single characters. // This test uses a set and so should not allow duplicates. final IntersectionSimilarity similarity = new IntersectionSimilarity<>(IntersectionSimilarityTest::toCharacterSet); // Expected: // size A or B = count of unique characters (exclude duplicates) // intersection = count of unique matching characters (exclude duplicates) assertIntersection(similarity, "", "", 0, 0, 0); assertIntersection(similarity, "a", "", 1, 0, 0); assertIntersection(similarity, "a", "a", 1, 1, 1); assertIntersection(similarity, "a", "b", 1, 1, 0); assertIntersection(similarity, "aa", "ab", 1, 2, 1); assertIntersection(similarity, "ab", "ab", 2, 2, 2); assertIntersection(similarity, "aaba", "abaa", 2, 2, 2); assertIntersection(similarity, "aaaa", "aa", 1, 1, 1); assertIntersection(similarity, "aa", "aaaa", 1, 1, 1); assertIntersection(similarity, "aaaa", "aaa", 1, 1, 1); assertIntersection(similarity, "aabab", "ababa", 2, 2, 2); assertIntersection(similarity, "the same", "the same", 7, 7, 7); assertIntersection(similarity, "abcdefghijklm", "ab_defg ijklm", 13, 13, 11); } @Test void testIntersectionUsingSetCharacterListCharacter() { // Compute using a custom converter that returns a Set and a List. // This is an edge-case test. final HashMap> converter = new HashMap<>(); final String sequence1 = "aabbccdd"; final String sequence2 = "aaaaaabbbfffff"; converter.put(sequence1, toCharacterSet(sequence1)); converter.put(sequence2, toCharacterList(sequence2)); final IntersectionSimilarity similarity = new IntersectionSimilarity<>(converter::get); // Expected: // size A = count of unique characters (exclude duplicates) // size B = sequence length // intersection = count of matching characters (exclude duplicates) assertIntersection(similarity, sequence1, sequence2, 4, sequence2.length(), 2); assertIntersection(similarity, sequence2, sequence1, sequence2.length(), 4, 2); } } JaccardDistanceTest.java000066400000000000000000000123111511432740600354210ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link JaccardDistance}. */ class JaccardDistanceTest { private static JaccardDistance classBeingTested; @BeforeAll public static void setUp() { classBeingTested = new JaccardDistance(); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testGettingJaccardDistance(final Class cls) { // Expected Jaccard distance = 1.0 - (intersect / union) assertEquals(0.0, classBeingTested.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, ""))); assertEquals(1.0, classBeingTested.apply(SimilarityInputTest.build(cls, "left"), SimilarityInputTest.build(cls, ""))); assertEquals(1.0, classBeingTested.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "right"))); assertEquals(1.0 - 3.0 / 4, classBeingTested.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog"))); assertEquals(1.0, classBeingTested.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant"))); assertEquals(1.0 - 2.0 / 9, classBeingTested.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(1.0 - 7.0 / 11, classBeingTested.apply(SimilarityInputTest.build(cls, "ABC Corporation"), SimilarityInputTest.build(cls, "ABC Corp"))); assertEquals(1.0 - 13.0 / 17, classBeingTested.apply(SimilarityInputTest.build(cls, "D N H Enterprises Inc"), SimilarityInputTest.build(cls, "D & H Enterprises, Inc."))); assertEquals(1.0 - 16.0 / 18, classBeingTested.apply(SimilarityInputTest.build(cls, "My Gym Children's Fitness Center"), SimilarityInputTest.build(cls, "My Gym. Childrens Fitness"))); assertEquals(1.0 - 9.0 / 10, classBeingTested.apply(SimilarityInputTest.build(cls, "PENNSYLVANIA"), SimilarityInputTest.build(cls, "PENNCISYLVNIA"))); assertEquals(1.0 - 1.0 / 8, classBeingTested.apply(SimilarityInputTest.build(cls, "left"), SimilarityInputTest.build(cls, "right"))); assertEquals(1.0 - 1.0 / 8, classBeingTested.apply(SimilarityInputTest.build(cls, "leettteft"), SimilarityInputTest.build(cls, "ritttght"))); assertEquals(0.0, classBeingTested.apply(SimilarityInputTest.build(cls, "the same string"), SimilarityInputTest.build(cls, "the same string"))); } @Test void testGettingJaccardDistanceCharSequence() { // Expected Jaccard distance = 1.0 - (intersect / union) assertEquals(0.0, classBeingTested.apply("", "")); assertEquals(1.0, classBeingTested.apply("left", "")); assertEquals(1.0, classBeingTested.apply("", "right")); assertEquals(1.0 - 3.0 / 4, classBeingTested.apply("frog", "fog")); assertEquals(1.0, classBeingTested.apply("fly", "ant")); assertEquals(1.0 - 2.0 / 9, classBeingTested.apply("elephant", "hippo")); assertEquals(1.0 - 7.0 / 11, classBeingTested.apply("ABC Corporation", "ABC Corp")); assertEquals(1.0 - 13.0 / 17, classBeingTested.apply("D N H Enterprises Inc", "D & H Enterprises, Inc.")); assertEquals(1.0 - 16.0 / 18, classBeingTested.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness")); assertEquals(1.0 - 9.0 / 10, classBeingTested.apply("PENNSYLVANIA", "PENNCISYLVNIA")); assertEquals(1.0 - 1.0 / 8, classBeingTested.apply("left", "right")); assertEquals(1.0 - 1.0 / 8, classBeingTested.apply("leettteft", "ritttght")); assertEquals(0.0, classBeingTested.apply("the same string", "the same string")); } @Test void testGettingJaccardDistanceNullNull() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply((String) null, null)); } @Test void testGettingJaccardDistanceNullString() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply(null, "right")); } @Test void testGettingJaccardDistanceStringNull() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply(" ", null)); } } JaccardSimilarityTest.java000066400000000000000000000130171511432740600360210ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link JaccardSimilarity}. */ class JaccardSimilarityTest { private static JaccardSimilarity classBeingTested; @BeforeAll public static void setUp() { classBeingTested = new JaccardSimilarity(); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testGettingJaccardSimilarity(final Class cls) { // Expected Jaccard similarity = (intersect / union) assertEquals(1.0, classBeingTested.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, ""))); assertEquals(0.0, classBeingTested.apply(SimilarityInputTest.build(cls, "left"), SimilarityInputTest.build(cls, ""))); assertEquals(0.0, classBeingTested.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "right"))); assertEquals(3.0 / 4, classBeingTested.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog"))); assertEquals(0.0, classBeingTested.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant"))); assertEquals(2.0 / 9, classBeingTested.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(7.0 / 11, classBeingTested.apply(SimilarityInputTest.build(cls, "ABC Corporation"), SimilarityInputTest.build(cls, "ABC Corp"))); assertEquals(13.0 / 17, classBeingTested.apply(SimilarityInputTest.build(cls, "D N H Enterprises Inc"), SimilarityInputTest.build(cls, "D & H Enterprises, Inc."))); assertEquals(16.0 / 18, classBeingTested.apply(SimilarityInputTest.build(cls, "My Gym Children's Fitness Center"), SimilarityInputTest.build(cls, "My Gym. Childrens Fitness"))); assertEquals(9.0 / 10, classBeingTested.apply(SimilarityInputTest.build(cls, "PENNSYLVANIA"), SimilarityInputTest.build(cls, "PENNCISYLVNIA"))); assertEquals(1.0 / 8, classBeingTested.apply(SimilarityInputTest.build(cls, "left"), SimilarityInputTest.build(cls, "right"))); assertEquals(1.0 / 8, classBeingTested.apply(SimilarityInputTest.build(cls, "leettteft"), SimilarityInputTest.build(cls, "ritttght"))); assertEquals(1.0, classBeingTested.apply(SimilarityInputTest.build(cls, "the same string"), SimilarityInputTest.build(cls, "the same string"))); } @Test void testGettingJaccardSimilarityCharSequence() { // Expected Jaccard similarity = (intersect / union) assertEquals(1.0, classBeingTested.apply("", "")); assertEquals(0.0, classBeingTested.apply("left", "")); assertEquals(0.0, classBeingTested.apply("", "right")); assertEquals(3.0 / 4, classBeingTested.apply("frog", "fog")); assertEquals(0.0, classBeingTested.apply("fly", "ant")); assertEquals(2.0 / 9, classBeingTested.apply("elephant", "hippo")); assertEquals(7.0 / 11, classBeingTested.apply("ABC Corporation", "ABC Corp")); assertEquals(13.0 / 17, classBeingTested.apply("D N H Enterprises Inc", "D & H Enterprises, Inc.")); assertEquals(16.0 / 18, classBeingTested.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness")); assertEquals(9.0 / 10, classBeingTested.apply("PENNSYLVANIA", "PENNCISYLVNIA")); assertEquals(1.0 / 8, classBeingTested.apply("left", "right")); assertEquals(1.0 / 8, classBeingTested.apply("leettteft", "ritttght")); assertEquals(1.0, classBeingTested.apply("the same string", "the same string")); } @Test void testGettingJaccardSimilarityNullNull() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply((String) null, null)); } @Test void testGettingJaccardSimilarityNullSimilarityInput() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply(null, new SimilarityCharacterInput("asdf"))); } @Test void testGettingJaccardSimilarityNullString() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply(null, "right")); } @Test void testGettingJaccardSimilaritySimilarityInputNull() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply(new SimilarityCharacterInput("asdf"), null)); } @Test void testGettingJaccardSimilarityStringNull() { assertThrows(IllegalArgumentException.class, () -> classBeingTested.apply(" ", null)); } } JaroWinklerDistanceTest.java000066400000000000000000000147311511432740600363310ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link JaroWinklerDistance}. */ class JaroWinklerDistanceTest { private static JaroWinklerDistance distance; @BeforeAll public static void setUp() { distance = new JaroWinklerDistance(); } @Test void testApply_NullSimilarityInput() { assertThrows(IllegalArgumentException.class, () -> distance.apply(null, new SimilarityCharacterInput("a"))); } @Test void testApply_SimilarityInputNull() { assertThrows(IllegalArgumentException.class, () -> distance.apply(new SimilarityCharacterInput("a"), null)); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testGetJaroWinklerDistance(final Class cls) { assertEquals(0.07501d, distance.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog")), 0.00001d); assertEquals(1.0d, distance.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant")), 0.00000000000000000001d); assertEquals(0.55834d, distance.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo")), 0.00001d); assertEquals(0.09334d, distance.apply(SimilarityInputTest.build(cls, "ABC Corporation"), SimilarityInputTest.build(cls, "ABC Corp")), 0.00001d); assertEquals(0.04749d, distance.apply(SimilarityInputTest.build(cls, "D N H Enterprises Inc"), SimilarityInputTest.build(cls, "D & H Enterprises, Inc.")), 0.00001d); assertEquals(0.058d, distance.apply(SimilarityInputTest.build(cls, "My Gym Children's Fitness Center"), SimilarityInputTest.build(cls, "My Gym. Childrens Fitness")), 0.00001d); assertEquals(0.101982d, distance.apply(SimilarityInputTest.build(cls, "PENNSYLVANIA"), SimilarityInputTest.build(cls, "PENNCISYLVNIA")), 0.00001d); assertEquals(0.028572d, distance.apply(SimilarityInputTest.build(cls, "/opt/software1"), SimilarityInputTest.build(cls, "/opt/software2")), 0.00001d); assertEquals(0.058334d, distance.apply(SimilarityInputTest.build(cls, "aaabcd"), SimilarityInputTest.build(cls, "aaacdb")), 0.00001d); assertEquals(0.088889d, distance.apply(SimilarityInputTest.build(cls, "John Horn"), SimilarityInputTest.build(cls, "John Hopkins")), 0.00001d); assertEquals(0d, distance.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "")), 0.00001d); assertEquals(0d, distance.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, "foo")), 0.00001d); assertEquals(1 - 0.94166d, distance.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, "foo ")), 0.00001d); assertEquals(1 - 0.90666d, distance.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, "foo ")), 0.00001d); assertEquals(1 - 0.86666d, distance.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, " foo ")), 0.00001d); assertEquals(1 - 0.51111d, distance.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, " foo")), 0.00001d); } @Test void testGetJaroWinklerDistance_NullNull() { assertThrows(IllegalArgumentException.class, () -> distance.apply((String) null, null)); } @Test void testGetJaroWinklerDistance_NullString() { assertThrows(IllegalArgumentException.class, () -> distance.apply(null, "clear")); } @Test void testGetJaroWinklerDistance_StringNull() { assertThrows(IllegalArgumentException.class, () -> distance.apply(" ", null)); } @Test void testGetJaroWinklerDistance_StringString() { assertEquals(0.07501d, distance.apply("frog", "fog"), 0.00001d); assertEquals(1.0d, distance.apply("fly", "ant"), 0.00000000000000000001d); assertEquals(0.55834d, distance.apply("elephant", "hippo"), 0.00001d); assertEquals(0.09334d, distance.apply("ABC Corporation", "ABC Corp"), 0.00001d); assertEquals(0.04749d, distance.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.00001d); assertEquals(0.058d, distance.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.00001d); assertEquals(0.101982d, distance.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.00001d); assertEquals(0.028572d, distance.apply("/opt/software1", "/opt/software2"), 0.00001d); assertEquals(0.058334d, distance.apply("aaabcd", "aaacdb"), 0.00001d); assertEquals(0.088889d, distance.apply("John Horn", "John Hopkins"), 0.00001d); assertEquals(0d, distance.apply("", ""), 0.00001d); assertEquals(0d, distance.apply("foo", "foo"), 0.00001d); assertEquals(1 - 0.94166d, distance.apply("foo", "foo "), 0.00001d); assertEquals(1 - 0.90666d, distance.apply("foo", "foo "), 0.00001d); assertEquals(1 - 0.86666d, distance.apply("foo", " foo "), 0.00001d); assertEquals(1 - 0.51111d, distance.apply("foo", " foo"), 0.00001d); } @Test void testMatches() { assertArrayEquals(new int[]{2, 0, 2}, JaroWinklerSimilarity.matches("ab", "aba")); } @SuppressWarnings("deprecation") @Test void testMatchesDeprecated() { assertArrayEquals(new int[]{2, 0, 2}, JaroWinklerDistance.matches("ab", "aba")); } } JaroWinklerSimilarityTest.java000066400000000000000000000165671511432740600367360ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link JaroWinklerSimilarity}. */ class JaroWinklerSimilarityTest { private static JaroWinklerSimilarity similarity; @BeforeAll public static void setUp() { similarity = new JaroWinklerSimilarity(); } /** * Wraps the string in a custom {@link CharSequence}. This ensures that using the {@link Object#equals(Object)} method on the input CharSequence to test for * equality will fail. * * @param string the string * @return the char sequence */ private static CharSequence wrap(final String string) { return new CharSequence() { @Override public char charAt(final int index) { return string.charAt(index); } @Override public boolean equals(final Object obj) { return string.equals(obj); } @Override public int hashCode() { return string.hashCode(); } @Override public int length() { return string.length(); } @Override public CharSequence subSequence(final int start, final int end) { return string.subSequence(start, end); } @Override public String toString() { return string; } }; } @Test void testApply_NullSimilarityInput() { assertThrows(IllegalArgumentException.class, () -> similarity.apply(null, new SimilarityCharacterInput("a"))); } @Test void testApply_SimilarityInputNull() { assertThrows(IllegalArgumentException.class, () -> similarity.apply(new SimilarityCharacterInput("a"), null)); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testGetJaroWinklerSimilarity(final Class cls) { assertEquals(1d, similarity.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "")), 0.00001d); assertEquals(1d, similarity.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, "foo")), 0.00001d); assertEquals(0.94166d, similarity.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, "foo ")), 0.00001d); assertEquals(0.90666d, similarity.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, "foo ")), 0.00001d); assertEquals(0.86666d, similarity.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, " foo ")), 0.00001d); assertEquals(0.51111d, similarity.apply(SimilarityInputTest.build(cls, "foo"), SimilarityInputTest.build(cls, " foo")), 0.00001d); assertEquals(0.92499d, similarity.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog")), 0.00001d); assertEquals(0.0d, similarity.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant")), 0.00000000000000000001d); assertEquals(0.44166d, similarity.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo")), 0.00001d); assertEquals(0.90666d, similarity.apply(SimilarityInputTest.build(cls, "ABC Corporation"), SimilarityInputTest.build(cls, "ABC Corp")), 0.00001d); assertEquals(0.95251d, similarity.apply(SimilarityInputTest.build(cls, "D N H Enterprises Inc"), SimilarityInputTest.build(cls, "D & H Enterprises, Inc.")), 0.00001d); assertEquals(0.942d, similarity.apply(SimilarityInputTest.build(cls, "My Gym Children's Fitness Center"), SimilarityInputTest.build(cls, "My Gym. Childrens Fitness")), 0.00001d); assertEquals(0.898018d, similarity.apply(SimilarityInputTest.build(cls, "PENNSYLVANIA"), SimilarityInputTest.build(cls, "PENNCISYLVNIA")), 0.00001d); assertEquals(0.971428d, similarity.apply(SimilarityInputTest.build(cls, "/opt/software1"), SimilarityInputTest.build(cls, "/opt/software2")), 0.00001d); assertEquals(0.941666d, similarity.apply(SimilarityInputTest.build(cls, "aaabcd"), SimilarityInputTest.build(cls, "aaacdb")), 0.00001d); assertEquals(0.911111d, similarity.apply(SimilarityInputTest.build(cls, "John Horn"), SimilarityInputTest.build(cls, "John Hopkins")), 0.00001d); } @Test void testGetJaroWinklerSimilarity_NullNull() { assertThrows(IllegalArgumentException.class, () -> similarity.apply((String) null, null)); } @Test void testGetJaroWinklerSimilarity_NullString() { assertThrows(IllegalArgumentException.class, () -> similarity.apply(null, "clear")); } @Test void testGetJaroWinklerSimilarity_StringNull() { assertThrows(IllegalArgumentException.class, () -> similarity.apply(" ", null)); } @Test void testGetJaroWinklerSimilarity_StringString() { assertEquals(1d, similarity.apply(wrap(""), ""), 0.00001d); assertEquals(1d, similarity.apply(wrap("foo"), "foo"), 0.00001d); assertEquals(0.94166d, similarity.apply(wrap("foo"), "foo "), 0.00001d); assertEquals(0.90666d, similarity.apply(wrap("foo"), "foo "), 0.00001d); assertEquals(0.86666d, similarity.apply(wrap("foo"), " foo "), 0.00001d); assertEquals(0.51111d, similarity.apply(wrap("foo"), " foo"), 0.00001d); assertEquals(0.92499d, similarity.apply(wrap("frog"), "fog"), 0.00001d); assertEquals(0.0d, similarity.apply(wrap("fly"), "ant"), 0.00000000000000000001d); assertEquals(0.44166d, similarity.apply(wrap("elephant"), "hippo"), 0.00001d); assertEquals(0.90666d, similarity.apply(wrap("ABC Corporation"), "ABC Corp"), 0.00001d); assertEquals(0.95251d, similarity.apply(wrap("D N H Enterprises Inc"), "D & H Enterprises, Inc."), 0.00001d); assertEquals(0.942d, similarity.apply(wrap("My Gym Children's Fitness Center"), "My Gym. Childrens Fitness"), 0.00001d); assertEquals(0.898018d, similarity.apply(wrap("PENNSYLVANIA"), "PENNCISYLVNIA"), 0.00001d); assertEquals(0.971428d, similarity.apply(wrap("/opt/software1"), "/opt/software2"), 0.00001d); assertEquals(0.941666d, similarity.apply(wrap("aaabcd"), "aaacdb"), 0.00001d); assertEquals(0.911111d, similarity.apply(wrap("John Horn"), "John Hopkins"), 0.00001d); } } LevenshteinDetailedDistanceTest.java000066400000000000000000000565751511432740600400360ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.apache.commons.text.TextStringBuilder; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; class LevenshteinDetailedDistanceTest { private static final LevenshteinDetailedDistance UNLIMITED_DISTANCE = LevenshteinDetailedDistance.getDefaultInstance(); @Test void testApplyThrowsIllegalArgumentExceptionAndCreatesLevenshteinDetailedDistanceTakingInteger() { assertThrows(IllegalArgumentException.class, () -> { final LevenshteinDetailedDistance levenshteinDetailedDistance = new LevenshteinDetailedDistance(0); final CharSequence charSequence = new TextStringBuilder(); levenshteinDetailedDistance.apply(charSequence, null); }); } @Test void testApplyWithNullSimilarityInput() { assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(0).apply((SimilarityInput) null, (SimilarityInput) null)); assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(0).apply(new SimilarityCharacterInput("asdf"), (SimilarityCharacterInput) null)); assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(0).apply((SimilarityCharacterInput) null, new SimilarityCharacterInput("asdf"))); assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(null).apply(new SimilarityCharacterInput("asdf"), (SimilarityCharacterInput) null)); assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(null).apply((SimilarityCharacterInput) null, new SimilarityCharacterInput("asdf"))); } @Test void testApplyWithNullString() { assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(0).apply((String) null, (String) null)); } @Test void testConstructorWithNegativeThreshold() { assertThrows(IllegalArgumentException.class, () -> new LevenshteinDetailedDistance(-1)); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testCreatesLevenshteinDetailedDistanceTakingInteger6(final Class cls) { final LevenshteinDetailedDistance levenshteinDetailedDistance = new LevenshteinDetailedDistance(0); final LevenshteinResults levenshteinResults = levenshteinDetailedDistance.apply("", "Distance: 38, Insert: 0, Delete: 0, Substitute: 0"); assertEquals(0, levenshteinResults.getSubstituteCount()); assertEquals(0, levenshteinResults.getDeleteCount()); assertEquals(0, levenshteinResults.getInsertCount()); assertEquals(-1, levenshteinResults.getDistance()); assertEquals(levenshteinResults, levenshteinDetailedDistance.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "Distance: 38, Insert: 0, Delete: 0, Substitute: 0"))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testEquals(final Class cls) { final LevenshteinDetailedDistance classBeingTested = LevenshteinDetailedDistance.getDefaultInstance(); LevenshteinResults actualResult = classBeingTested.apply(SimilarityInputTest.build(cls, "hello"), SimilarityInputTest.build(cls, "hallo")); LevenshteinResults expectedResult = new LevenshteinResults(1, 0, 0, 1); assertEquals(expectedResult, actualResult); assertEquals(classBeingTested.apply("zzzzzzzz", "hippo"), classBeingTested.apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo"))); actualResult = classBeingTested.apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo")); expectedResult = new LevenshteinResults(8, 0, 3, 5); assertEquals(expectedResult, actualResult); assertEquals(actualResult, actualResult); // intentionally added actualResult = classBeingTested.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "")); expectedResult = new LevenshteinResults(0, 0, 0, 0); assertEquals(expectedResult, actualResult); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetDefaultInstanceOne(final Class cls) { final LevenshteinDetailedDistance levenshteinDetailedDistance = LevenshteinDetailedDistance.getDefaultInstance(); final LevenshteinResults levenshteinResults = levenshteinDetailedDistance.apply( SimilarityInputTest.build(cls, "Distance: -2147483643, Insert: 0, Delete: 0, Substitute: 0"), SimilarityInputTest.build(cls, "Distance: 0, Insert: 2147483536, Delete: 0, Substitute: 0")); assertEquals(21, levenshteinResults.getDistance()); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetDefaultInstanceTwo(final Class cls) { final LevenshteinDetailedDistance levenshteinDetailedDistance = LevenshteinDetailedDistance.getDefaultInstance(); final LevenshteinResults levenshteinResults = levenshteinDetailedDistance.apply("Distance: 2147483647, Insert: 0, Delete: 0, Substitute: 0", "Distance: 0, Insert: 2147483647, Delete: 0, Substitute: 0"); assertEquals(20, levenshteinResults.getDistance()); assertEquals(levenshteinResults, levenshteinDetailedDistance.apply(SimilarityInputTest.build(cls, "Distance: 2147483647, Insert: 0, Delete: 0, Substitute: 0"), SimilarityInputTest.build(cls, "Distance: 0, Insert: 2147483647, Delete: 0, Substitute: 0"))); } @Test void testGetLevenshteinDetailedDistance_NullString() { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply("a", null)); } @Test void testGetLevenshteinDetailedDistance_NullStringInt() { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply(null, "a")); } @Test void testGetLevenshteinDetailedDistance_StringNull() { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply(null, "a")); } @Test void testGetLevenshteinDetailedDistance_StringNullInt() { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply("a", null)); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDetailedDistance_StringString(final Class cls) { LevenshteinResults result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "")); assertEquals(0, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "a")); assertEquals(1, result.getDistance()); assertEquals(1, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, "")); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(7, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog")); assertEquals(1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(1, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant")); assertEquals(3, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(3, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo")); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(3, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "elephant")); assertEquals(7, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "zzzzzzzz")); assertEquals(8, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(5, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo")); assertEquals(8, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(3, result.getDeleteCount()); assertEquals(5, result.getSubstituteCount()); result = UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hello"), SimilarityInputTest.build(cls, "hallo")); assertEquals(1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); } @Test void testGetLevenshteinDetailedDistance_StringStringInt() { LevenshteinResults result = new LevenshteinDetailedDistance(0).apply("", ""); assertEquals(0, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(8).apply("aaapppp", ""); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(7, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(7).apply("aaapppp", ""); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(7, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(6).apply("aaapppp", ""); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(0).apply("b", "a"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(0).apply("a", "b"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(0).apply("aa", "aa"); assertEquals(0, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(2).apply("aa", "aa"); assertEquals(0, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(2).apply("aaa", "bbb"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(3).apply("aaa", "bbb"); assertEquals(3, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(3, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(10).apply("aaaaaa", "b"); assertEquals(6, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(5, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(8).apply("aaapppp", "b"); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(6, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(4).apply("a", "bbb"); assertEquals(3, result.getDistance()); assertEquals(2, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(7).apply("aaapppp", "b"); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(6, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(3).apply("a", "bbb"); assertEquals(3, result.getDistance()); assertEquals(2, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(2).apply("a", "bbb"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(2).apply("bbb", "a"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(6).apply("aaapppp", "b"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(1).apply("a", "bbb"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(1).apply("bbb", "a"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(1).apply("12345", "1234567"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(1).apply("1234567", "12345"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(1).apply("frog", "fog"); assertEquals(1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(1, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(3).apply("fly", "ant"); assertEquals(3, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(3, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(7).apply("elephant", "hippo"); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(3, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(6).apply("elephant", "hippo"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(7).apply("hippo", "elephant"); assertEquals(7, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(7).apply("hippo", "elephant"); assertEquals(7, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(6).apply("hippo", "elephant"); assertEquals(-1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(8).apply("hippo", "zzzzzzzz"); assertEquals(8, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(5, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(8).apply("zzzzzzzz", "hippo"); assertEquals(8, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(3, result.getDeleteCount()); assertEquals(5, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(1).apply("hello", "hallo"); assertEquals(1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("frog", "fog"); assertEquals(1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(1, result.getDeleteCount()); assertEquals(0, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("fly", "ant"); assertEquals(3, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(3, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("elephant", "hippo"); assertEquals(7, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(3, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hippo", "elephant"); assertEquals(7, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(4, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hippo", "zzzzzzzz"); assertEquals(8, result.getDistance()); assertEquals(3, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(5, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("zzzzzzzz", "hippo"); assertEquals(8, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(3, result.getDeleteCount()); assertEquals(5, result.getSubstituteCount()); result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hello", "hallo"); assertEquals(1, result.getDistance()); assertEquals(0, result.getInsertCount()); assertEquals(0, result.getDeleteCount()); assertEquals(1, result.getSubstituteCount()); } @Test void testGetThreshold() { final LevenshteinDetailedDistance levenshteinDetailedDistance = new LevenshteinDetailedDistance(0); assertEquals(0, levenshteinDetailedDistance.getThreshold()); } @Test void testHashCode() { final LevenshteinDetailedDistance classBeingTested = LevenshteinDetailedDistance.getDefaultInstance(); LevenshteinResults actualResult = classBeingTested.apply("aaapppp", ""); LevenshteinResults expectedResult = new LevenshteinResults(7, 0, 7, 0); assertEquals(expectedResult.hashCode(), actualResult.hashCode()); actualResult = classBeingTested.apply("frog", "fog"); expectedResult = new LevenshteinResults(1, 0, 1, 0); assertEquals(expectedResult.hashCode(), actualResult.hashCode()); actualResult = classBeingTested.apply("elephant", "hippo"); expectedResult = new LevenshteinResults(7, 0, 3, 4); assertEquals(expectedResult.hashCode(), actualResult.hashCode()); } @Test void testToString() { final LevenshteinDetailedDistance classBeingTested = LevenshteinDetailedDistance.getDefaultInstance(); LevenshteinResults actualResult = classBeingTested.apply("fly", "ant"); LevenshteinResults expectedResult = new LevenshteinResults(3, 0, 0, 3); assertEquals(expectedResult.toString(), actualResult.toString()); actualResult = classBeingTested.apply("hippo", "elephant"); expectedResult = new LevenshteinResults(7, 3, 0, 4); assertEquals(expectedResult.toString(), actualResult.toString()); actualResult = classBeingTested.apply("", "a"); expectedResult = new LevenshteinResults(1, 1, 0, 0); assertEquals(expectedResult.toString(), actualResult.toString()); } } LevenshteinDistanceTest.java000066400000000000000000000317671511432740600363760ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link LevenshteinDistance}. */ class LevenshteinDistanceTest { private static final LevenshteinDistance UNLIMITED_DISTANCE = LevenshteinDistance.getDefaultInstance(); @Test void testApplyThrowsIllegalArgumentExceptionSimilarityInput() { assertThrows(IllegalArgumentException.class, () -> new LevenshteinDistance(0).apply((SimilarityInput) null, (SimilarityInput) null)); assertThrows(IllegalArgumentException.class, () -> new LevenshteinDistance(0).apply(new SimilarityCharacterInput("asdf"), (SimilarityCharacterInput) null)); assertThrows(IllegalArgumentException.class, () -> new LevenshteinDistance(0).apply((SimilarityCharacterInput) null, new SimilarityCharacterInput("asdf"))); } @Test void testApplyThrowsIllegalArgumentExceptionString() { assertThrows(IllegalArgumentException.class, () -> new LevenshteinDistance(0).apply((String) null, (String) null)); } @Test void testConstructorWithNegativeThreshold() { assertThrows(IllegalArgumentException.class, () -> new LevenshteinDistance(-1)); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance(final Class cls) { assertEquals(0, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, ""))); assertEquals(1, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "a"))); assertEquals(7, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, ""))); assertEquals(1, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog"))); assertEquals(3, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant"))); assertEquals(7, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(7, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "elephant"))); assertEquals(8, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "zzzzzzzz"))); assertEquals(8, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(1, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hello"), SimilarityInputTest.build(cls, "hallo"))); } @Test void testGetLevenshteinDistance_EmptyStringString() { assertEquals(-1, new LevenshteinDistance(0).apply(new SimilarityCharacterInput(""), new SimilarityCharacterInput("asdf"))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance_NullString(final Class cls) { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, null))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance_NullStringInt(final Class cls) { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, null), SimilarityInputTest.build(cls, "a"))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance_StringNull(final Class cls) { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, null), SimilarityInputTest.build(cls, "a"))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance_StringNullInt(final Class cls) { assertThrows(IllegalArgumentException.class, () -> UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, null))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance_StringString(final Class cls) { assertEquals(0, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, ""))); assertEquals(1, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, "a"))); assertEquals(7, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, ""))); assertEquals(1, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog"))); assertEquals(3, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant"))); assertEquals(7, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(7, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "elephant"))); assertEquals(8, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "zzzzzzzz"))); assertEquals(8, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(1, UNLIMITED_DISTANCE.apply(SimilarityInputTest.build(cls, "hello"), SimilarityInputTest.build(cls, "hallo"))); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputs()") void testGetLevenshteinDistance_StringStringInt(final Class cls) { // empty strings assertEquals(0, new LevenshteinDistance(0).apply(SimilarityInputTest.build(cls, ""), SimilarityInputTest.build(cls, ""))); assertEquals(7, new LevenshteinDistance(8).apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, ""))); assertEquals(7, new LevenshteinDistance(7).apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, ""))); assertEquals(-1, new LevenshteinDistance(6).apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, ""))); // unequal strings, zero threshold assertEquals(-1, new LevenshteinDistance(0).apply(SimilarityInputTest.build(cls, "b"), SimilarityInputTest.build(cls, "a"))); assertEquals(-1, new LevenshteinDistance(0).apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, "b"))); // equal strings assertEquals(0, new LevenshteinDistance(0).apply(SimilarityInputTest.build(cls, "aa"), SimilarityInputTest.build(cls, "aa"))); assertEquals(0, new LevenshteinDistance(2).apply(SimilarityInputTest.build(cls, "aa"), SimilarityInputTest.build(cls, "aa"))); // same length assertEquals(-1, new LevenshteinDistance(2).apply(SimilarityInputTest.build(cls, "aaa"), SimilarityInputTest.build(cls, "bbb"))); assertEquals(3, new LevenshteinDistance(3).apply(SimilarityInputTest.build(cls, "aaa"), SimilarityInputTest.build(cls, "bbb"))); // big stripe assertEquals(6, new LevenshteinDistance(10).apply(SimilarityInputTest.build(cls, "aaaaaa"), SimilarityInputTest.build(cls, "b"))); // distance less than threshold assertEquals(7, new LevenshteinDistance(8).apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, "b"))); assertEquals(3, new LevenshteinDistance(4).apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, "bbb"))); // distance equal to threshold assertEquals(7, new LevenshteinDistance(7).apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, "b"))); assertEquals(3, new LevenshteinDistance(3).apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, "bbb"))); // distance greater than threshold assertEquals(-1, new LevenshteinDistance(2).apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, "bbb"))); assertEquals(-1, new LevenshteinDistance(2).apply(SimilarityInputTest.build(cls, "bbb"), SimilarityInputTest.build(cls, "a"))); assertEquals(-1, new LevenshteinDistance(6).apply(SimilarityInputTest.build(cls, "aaapppp"), SimilarityInputTest.build(cls, "b"))); // stripe runs off array, strings not similar assertEquals(-1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "a"), SimilarityInputTest.build(cls, "bbb"))); assertEquals(-1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "bbb"), SimilarityInputTest.build(cls, "a"))); // stripe runs off array, strings are similar assertEquals(-1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "12345"), SimilarityInputTest.build(cls, "1234567"))); assertEquals(-1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "1234567"), SimilarityInputTest.build(cls, "12345"))); // old getLevenshteinDistance test cases assertEquals(1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog"))); assertEquals(3, new LevenshteinDistance(3).apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant"))); assertEquals(7, new LevenshteinDistance(7).apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(-1, new LevenshteinDistance(6).apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(7, new LevenshteinDistance(7).apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "elephant"))); assertEquals(-1, new LevenshteinDistance(6).apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "elephant"))); assertEquals(8, new LevenshteinDistance(8).apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "zzzzzzzz"))); assertEquals(8, new LevenshteinDistance(8).apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "hello"), SimilarityInputTest.build(cls, "hallo"))); assertEquals(1, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "frog"), SimilarityInputTest.build(cls, "fog"))); assertEquals(3, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "fly"), SimilarityInputTest.build(cls, "ant"))); assertEquals(7, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "elephant"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(7, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "elephant"))); assertEquals(8, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "hippo"), SimilarityInputTest.build(cls, "zzzzzzzz"))); assertEquals(8, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "zzzzzzzz"), SimilarityInputTest.build(cls, "hippo"))); assertEquals(1, new LevenshteinDistance(Integer.MAX_VALUE).apply(SimilarityInputTest.build(cls, "hello"), SimilarityInputTest.build(cls, "hallo"))); assertEquals(-1, new LevenshteinDistance(1).apply(SimilarityInputTest.build(cls, "abc"), SimilarityInputTest.build(cls, "acb"))); } @Test void testGetThresholdDirectlyAfterObjectInstantiation() { assertNull(LevenshteinDistance.getDefaultInstance().getThreshold()); } } LevenshteinResultsTest.java000066400000000000000000000053541511432740600362760ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; class LevenshteinResultsTest { @Test void testEqualsDifferenceInSubstitutionCount() { final Integer integer = 1662; final LevenshteinResults levenshteinResults = new LevenshteinResults(integer, integer, integer, integer); final LevenshteinResults levenshteinResultsTwo = new LevenshteinResults(integer, integer, integer, null); assertFalse(levenshteinResults.equals(levenshteinResultsTwo)); } @Test void testEqualsReturningFalse() { final Integer integerOne = 1662; final Integer integerTwo = 1164; final LevenshteinResults levenshteinResults = new LevenshteinResults(integerOne, integerOne, integerOne, integerOne); final LevenshteinResults levenshteinResultsTwo = new LevenshteinResults(integerOne, integerOne, integerTwo, integerTwo); assertFalse(levenshteinResults.equals(levenshteinResultsTwo)); } @Test void testEqualsSameObject() { final Integer integer = 1662; final LevenshteinResults levenshteinResults = new LevenshteinResults(integer, integer, integer, null); assertTrue(levenshteinResults.equals(levenshteinResults)); } @Test void testEqualsWithNonNull() { final Integer integer = 1; final LevenshteinResults levenshteinResults = new LevenshteinResults(null, integer, integer, null); final LevenshteinResults levenshteinResultsTwo = new LevenshteinResults(null, null, null, null); assertFalse(levenshteinResults.equals(levenshteinResultsTwo)); } @Test void testEqualsWithNull() { final Integer integer = -647; final LevenshteinResults levenshteinResults = new LevenshteinResults(integer, null, null, integer); assertFalse(levenshteinResults.equals(null)); } } LongestCommonSubsequenceDistanceTest.java000066400000000000000000000053361511432740600410720ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; /** * Tests {@link LongestCommonSubsequenceDistance}. */ class LongestCommonSubsequenceDistanceTest { private static LongestCommonSubsequenceDistance subject; @BeforeAll public static void setup() { subject = new LongestCommonSubsequenceDistance(); } @Test void testGettingLongestCommonSubsequenceDistance() { assertEquals(0, subject.apply("", "")); assertEquals(4, subject.apply("left", "")); assertEquals(5, subject.apply("", "right")); assertEquals(1, subject.apply("frog", "fog")); assertEquals(6, subject.apply("fly", "ant")); assertEquals(11, subject.apply("elephant", "hippo")); assertEquals(7, subject.apply("ABC Corporation", "ABC Corp")); assertEquals(4, subject.apply("D N H Enterprises Inc", "D & H Enterprises, Inc.")); assertEquals(9, subject.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness")); assertEquals(3, subject.apply("PENNSYLVANIA", "PENNCISYLVNIA")); assertEquals(7, subject.apply("left", "right")); assertEquals(9, subject.apply("leettteft", "ritttght")); assertEquals(0, subject.apply("the same string", "the same string")); } @Test void testGettingLongestCommonSubsequenceDistanceNullNull() { assertThrows(IllegalArgumentException.class, () -> subject.apply(null, null)); } @Test void testGettingLongestCommonSubsequenceDistanceNullString() { assertThrows(IllegalArgumentException.class, () -> subject.apply(null, "right")); } @Test void testGettingLongestCommonSubsequenceDistanceStringNull() { assertThrows(IllegalArgumentException.class, () -> subject.apply(" ", null)); } } LongestCommonSubsequenceTest.java000066400000000000000000000151321511432740600374120ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; /** * Tests {@link LongestCommonSubsequence}. */ class LongestCommonSubsequenceTest { private static LongestCommonSubsequence subject; @BeforeAll public static void setup() { subject = new LongestCommonSubsequence(); } @Test @SuppressWarnings("deprecation") void testGettingLogestCommonSubsequenceNullNull() { assertThrows(IllegalArgumentException.class, () -> subject.logestCommonSubsequence(null, null)); } @Test @SuppressWarnings("deprecation") void testGettingLogestCommonSubsequenceNullString() { assertThrows(IllegalArgumentException.class, () -> subject.logestCommonSubsequence(null, "right")); } @Test @SuppressWarnings("deprecation") void testGettingLogestCommonSubsequenceStringNull() { assertThrows(IllegalArgumentException.class, () -> subject.logestCommonSubsequence(" ", null)); } @Test void testGettingLongestCommonSubsequenceApplyNullNull() { assertThrows(IllegalArgumentException.class, () -> subject.apply(null, null)); } @Test void testGettingLongestCommonSubsequenceApplyNullString() { assertThrows(IllegalArgumentException.class, () -> subject.apply(null, "right")); } @Test void testGettingLongestCommonSubsequenceApplyStringNull() { assertThrows(IllegalArgumentException.class, () -> subject.apply(" ", null)); } @Test void testGettingLongestCommonSubsequenceNullNull() { assertThrows(IllegalArgumentException.class, () -> subject.longestCommonSubsequence(null, null)); } @Test void testGettingLongestCommonSubsequenceNullString() { assertThrows(IllegalArgumentException.class, () -> subject.longestCommonSubsequence(null, "right")); } @Test void testGettingLongestCommonSubsequenceStringNull() { assertThrows(IllegalArgumentException.class, () -> subject.longestCommonSubsequence(" ", null)); } @Test @Deprecated void testLogestCommonSubsequence() { assertEquals("", subject.logestCommonSubsequence("", "")); assertEquals("", subject.logestCommonSubsequence("left", "")); assertEquals("", subject.logestCommonSubsequence("", "right")); assertEquals("fog", subject.logestCommonSubsequence("frog", "fog")); assertEquals("", subject.logestCommonSubsequence("fly", "ant")); assertEquals("h", subject.logestCommonSubsequence("elephant", "hippo")); assertEquals("ABC Corp", subject.logestCommonSubsequence("ABC Corporation", "ABC Corp")); assertEquals("D H Enterprises Inc", subject.logestCommonSubsequence("D N H Enterprises Inc", "D & H Enterprises, Inc.")); assertEquals("My Gym Childrens Fitness", subject.logestCommonSubsequence("My Gym Children's Fitness Center", "My Gym. Childrens Fitness")); assertEquals("PENNSYLVNIA", subject.logestCommonSubsequence("PENNSYLVANIA", "PENNCISYLVNIA")); assertEquals("t", subject.logestCommonSubsequence("left", "right")); assertEquals("tttt", subject.logestCommonSubsequence("leettteft", "ritttght")); assertEquals("the same string", subject.logestCommonSubsequence("the same string", "the same string")); } @Test void testLongestCommonSubsequence() { assertEquals("", subject.longestCommonSubsequence("", "")); assertEquals("", subject.longestCommonSubsequence("left", "")); assertEquals("", subject.longestCommonSubsequence("", "right")); assertEquals("fog", subject.longestCommonSubsequence("frog", "fog")); assertEquals("", subject.longestCommonSubsequence("fly", "ant")); assertEquals("h", subject.longestCommonSubsequence("elephant", "hippo")); assertEquals("ABC Corp", subject.longestCommonSubsequence("ABC Corporation", "ABC Corp")); assertEquals("D H Enterprises Inc", subject.longestCommonSubsequence("D N H Enterprises Inc", "D & H Enterprises, Inc.")); assertEquals("My Gym Childrens Fitness", subject.longestCommonSubsequence("My Gym Children's Fitness Center", "My Gym. Childrens Fitness")); assertEquals("PENNSYLVNIA", subject.longestCommonSubsequence("PENNSYLVANIA", "PENNCISYLVNIA")); assertEquals("t", subject.longestCommonSubsequence("left", "right")); assertEquals("tttt", subject.longestCommonSubsequence("leettteft", "ritttght")); assertEquals("the same string", subject.longestCommonSubsequence("the same string", "the same string")); } @Test void testLongestCommonSubsequenceApply() { assertEquals(0, subject.apply("", "")); assertEquals(0, subject.apply("left", "")); assertEquals(0, subject.apply("", "right")); assertEquals(3, subject.apply("frog", "fog")); assertEquals(0, subject.apply("fly", "ant")); assertEquals(1, subject.apply("elephant", "hippo")); assertEquals(8, subject.apply("ABC Corporation", "ABC Corp")); assertEquals(20, subject.apply("D N H Enterprises Inc", "D & H Enterprises, Inc.")); assertEquals(24, subject.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness")); assertEquals(11, subject.apply("PENNSYLVANIA", "PENNCISYLVNIA")); assertEquals(1, subject.apply("left", "right")); assertEquals(4, subject.apply("leettteft", "ritttght")); assertEquals(15, subject.apply("the same string", "the same string")); } @Test void testLongestCommonSubstringLengthArray() { assertArrayEquals(new int[][]{ {0, 0, 0, 0}, {0, 1, 1, 1}, {0, 1, 2, 2}}, subject.longestCommonSubstringLengthArray("ab", "abc")); } } ParameterizedEditDistanceFromTest.java000066400000000000000000000052351511432740600403270ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link EditDistanceFrom}. * * @param The {@link EditDistance} return type. */ public class ParameterizedEditDistanceFromTest { public static Stream parameters() { return Stream.of( Arguments.of(new HammingDistance(), "Sam I am.", "Ham I am.", 1), Arguments.of(new HammingDistance(), "Japtheth, Ham, Shem", "Japtheth, HAM, Shem", 2), Arguments.of(new HammingDistance(), "Hamming", "Hamming", 0), Arguments.of(LevenshteinDistance.getDefaultInstance(), "Apache", "a patchy", 4), Arguments.of(LevenshteinDistance.getDefaultInstance(), "go", "no go", 3), Arguments.of(LevenshteinDistance.getDefaultInstance(), "go", "go", 0), Arguments.of(new LevenshteinDistance(4), "Apache", "a patchy", 4), Arguments.of(new LevenshteinDistance(4), "go", "no go", 3), Arguments.of(new LevenshteinDistance(0), "go", "go", 0), Arguments.of( (EditDistance) (left, right) -> left == right || left != null && left.equals(right), "Bob's your uncle.", "Every good boy does fine.", false)); } @ParameterizedTest @MethodSource("parameters") void test(final EditDistance editDistance, final CharSequence left, final CharSequence right, final R distance) { final EditDistanceFrom editDistanceFrom = new EditDistanceFrom<>(editDistance, left); assertEquals(distance, editDistanceFrom.apply(right)); } } ParameterizedLevenshteinDistanceTest.java000066400000000000000000000077211511432740600411040ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link LevenshteinDistance}. */ class ParameterizedLevenshteinDistanceTest { public static Stream parameters() { // @formatter:off return Stream.of( /* empty strings */ Arguments.of(0, "", "", 0), Arguments.of(8, "aaapppp", "", 7), Arguments.of(7, "aaapppp", "", 7), Arguments.of(6, "aaapppp", "", -1), /* unequal strings, zero threshold */ Arguments.of(0, "b", "a", -1), Arguments.of(0, "a", "b", -1), /* equal strings */ Arguments.of(0, "aa", "aa", 0), Arguments.of(2, "aa", "aa", 0), /* same length */ Arguments.of(2, "aaa", "bbb", -1), Arguments.of(3, "aaa", "bbb", 3), /* big stripe */ Arguments.of(10, "aaaaaa", "b", 6), /* distance less than threshold */ Arguments.of(8, "aaapppp", "b", 7), Arguments.of(4, "a", "bbb", 3), /* distance equal to threshold */ Arguments.of(7, "aaapppp", "b", 7), Arguments.of(3, "a", "bbb", 3), /* distance greater than threshold */ Arguments.of(2, "a", "bbb", -1), Arguments.of(2, "bbb", "a", -1), Arguments.of(6, "aaapppp", "b", -1), /* stripe runs off array, strings not similar */ Arguments.of(1, "a", "bbb", -1), Arguments.of(1, "bbb", "a", -1), /* stripe runs off array, strings are similar */ Arguments.of(1, "12345", "1234567", -1), Arguments.of(1, "1234567", "12345", -1), /* old getLevenshteinDistance test cases */ Arguments.of(1, "frog", "fog", 1), Arguments.of(3, "fly", "ant", 3), Arguments.of(7, "elephant", "hippo", 7), Arguments.of(6, "elephant", "hippo", -1), Arguments.of(7, "hippo", "elephant", 7), Arguments.of(6, "hippo", "elephant", -1), Arguments.of(8, "hippo", "zzzzzzzz", 8), Arguments.of(8, "zzzzzzzz", "hippo", 8), Arguments.of(1, "hello", "hallo", 1), Arguments.of(Integer.MAX_VALUE, "frog", "fog", 1), Arguments.of(Integer.MAX_VALUE, "fly", "ant", 3), Arguments.of(Integer.MAX_VALUE, "elephant", "hippo", 7), Arguments.of(Integer.MAX_VALUE, "hippo", "elephant", 7), Arguments.of(Integer.MAX_VALUE, "hippo", "zzzzzzzz", 8), Arguments.of(Integer.MAX_VALUE, "zzzzzzzz", "hippo", 8), Arguments.of(Integer.MAX_VALUE, "hello", "hallo", 1)); // @formatter:on } @ParameterizedTest @MethodSource("parameters") void test(final Integer threshold, final CharSequence left, final CharSequence right, final Integer distance) { assertEquals(distance, new LevenshteinDistance(threshold).apply(left, right)); } } ParameterizedSimilarityScoreFromTest.java000066400000000000000000000042201511432740600411020ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link SimilarityScoreFrom}. * * @param The {@link SimilarityScore} return type. */ public class ParameterizedSimilarityScoreFromTest { public static Stream parameters() { return Stream.of(Arguments.of(LevenshteinDistance.getDefaultInstance(), "elephant", "hippo", 7), Arguments.of(LevenshteinDistance.getDefaultInstance(), "hippo", "elephant", 7), Arguments.of(LevenshteinDistance.getDefaultInstance(), "hippo", "zzzzzzzz", 8), Arguments.of((SimilarityScore) (left, right) -> left == right || left != null && left.equals(right), "Bob's your uncle.", "Every good boy does fine.", false)); } @ParameterizedTest @MethodSource("parameters") void test(final SimilarityScore similarityScore, final CharSequence left, final CharSequence right, final R distance) { final SimilarityScoreFrom similarityScoreFrom = new SimilarityScoreFrom<>(similarityScore, left); assertEquals(distance, similarityScoreFrom.apply(right)); } } SimilarityCharacterInputTest.java000066400000000000000000000105751511432740600374140ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link SimilarityCharacterInput}. */ class SimilarityCharacterInputTest { @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testEquals(final Class cls) { final SimilarityInput similarityInput1 = SimilarityInputTest.build(cls, ""); final SimilarityInput similarityInput2 = SimilarityInputTest.build(cls, ""); assertEquals(similarityInput1, similarityInput2); assertEquals(similarityInput1, similarityInput1); assertEquals(similarityInput2, similarityInput1); assertEquals(similarityInput2, similarityInput2); final SimilarityInput similarityInput3 = SimilarityInputTest.build(cls, "3"); final SimilarityInput similarityInput4 = SimilarityInputTest.build(cls, "4"); assertNotEquals(similarityInput1, similarityInput4); assertNotEquals(similarityInput2, similarityInput4); assertNotEquals(similarityInput3, similarityInput4); assertNotEquals(similarityInput1, null); assertNotEquals(similarityInput1, new Object()); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testHashCode(final Class cls) { final SimilarityInput similarityInput1 = SimilarityInputTest.build(cls, ""); final SimilarityInput similarityInput2 = SimilarityInputTest.build(cls, ""); assertEquals(similarityInput1.hashCode(), similarityInput2.hashCode()); assertEquals(similarityInput1.hashCode(), similarityInput1.hashCode()); assertEquals(similarityInput2.hashCode(), similarityInput1.hashCode()); assertEquals(similarityInput2.hashCode(), similarityInput2.hashCode()); final SimilarityInput similarityInput3 = SimilarityInputTest.build(cls, "3"); final SimilarityInput similarityInput4 = SimilarityInputTest.build(cls, "4"); assertNotEquals(similarityInput1.hashCode(), similarityInput4.hashCode()); assertNotEquals(similarityInput2.hashCode(), similarityInput4.hashCode()); assertNotEquals(similarityInput3.hashCode(), similarityInput4.hashCode()); } @ParameterizedTest @MethodSource("org.apache.commons.text.similarity.SimilarityInputTest#similarityInputsEquals()") void testToString(final Class cls) { final SimilarityInput similarityInput1 = SimilarityInputTest.build(cls, ""); final SimilarityInput similarityInput2 = SimilarityInputTest.build(cls, ""); assertEquals(similarityInput1.toString(), similarityInput2.toString()); assertEquals(similarityInput1.toString(), similarityInput1.toString()); assertEquals(similarityInput2.toString(), similarityInput1.toString()); assertEquals(similarityInput2.toString(), similarityInput2.toString()); final SimilarityInput similarityInput3 = SimilarityInputTest.build(cls, "3"); final SimilarityInput similarityInput4 = SimilarityInputTest.build(cls, "4"); assertNotEquals(similarityInput1.toString(), similarityInput4.toString()); assertNotEquals(similarityInput2.toString(), similarityInput4.toString()); assertNotEquals(similarityInput3.toString(), similarityInput4.toString()); } } SimilarityInputTest.java000066400000000000000000000064171511432740600355770ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Objects; import java.util.stream.Stream; import org.apache.commons.text.TextStringBuilder; import org.junit.jupiter.api.Test; /** * Tests {@link SimilarityInput}. */ public class SimilarityInputTest { public static final class SimilarityInputFixture implements SimilarityInput { private final CharSequence value; public SimilarityInputFixture(final String value) { this.value = Objects.requireNonNull(value); } @Override public Object at(final int i) { return value.charAt(i); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SimilarityInputFixture other = (SimilarityInputFixture) obj; return Objects.equals(value, other.value); } @Override public int hashCode() { return Objects.hash(value); } @Override public int length() { return value.length(); } } static SimilarityInput build(final Class fixtureClass, final String value) { if (value == null) { return null; } try { // Use the Class' constructor with a single String. return SimilarityInput.input((Object) fixtureClass.getConstructor(String.class).newInstance(value)); } catch (final ReflectiveOperationException e) { throw new AssertionError(e); } } static Stream> similarityInputs() { return Stream.of(SimilarityInputTest.SimilarityInputFixture.class, String.class, StringBuilder.class, StringBuffer.class, TextStringBuilder.class); } static Stream> similarityInputsEquals() { return Stream.of(SimilarityInputTest.SimilarityInputFixture.class, String.class, TextStringBuilder.class); } @Test void testInput() throws Exception { final SimilarityInput input = SimilarityInput.input("a"); assertEquals(1, input.length()); assertThrows(IllegalArgumentException.class, () -> SimilarityInput.input(new Object())); } } SimilarityScoreFromTest.java000066400000000000000000000036471511432740600364010ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class SimilarityScoreFromTest { private LongestCommonSubsequence longestCommonSubsequence; private SimilarityScoreFrom similarityScoreFrom; @BeforeEach void doBeforeEachTest() { longestCommonSubsequence = new LongestCommonSubsequence(); similarityScoreFrom = new SimilarityScoreFrom<>(longestCommonSubsequence, "asdf"); } @Test void testApply() { assertEquals(1, similarityScoreFrom.apply("s")); } @Test void testFailsToCreateSimilarityScoreFromThrowsIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> new SimilarityScoreFrom<>(null, "")); } @Test void testGetLeft() { assertEquals("asdf", similarityScoreFrom.getLeft()); } @Test void testGetSimilarityScore() { assertEquals(longestCommonSubsequence, similarityScoreFrom.getSimilarityScore()); } } StringMetricFromTest.java000066400000000000000000000046461511432740600356710ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/similarity/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.similarity; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; /** * Tests {@link EditDistanceFrom}. */ class StringMetricFromTest { @Test void testEquivalence() { final EditDistance metric = LevenshteinDistance.getDefaultInstance(); final String left = "Apache"; final String right = "a patchy"; final Integer distance = 4; final EditDistanceFrom metricFrom = new EditDistanceFrom<>(metric, left); assertEquals(distance, metricFrom.apply(right)); assertEquals(metric.apply(left, right), metricFrom.apply(right)); } @Test void testJavadocExample() { final EditDistance metric = LevenshteinDistance.getDefaultInstance(); final String target = "Apache"; final EditDistanceFrom metricFrom = new EditDistanceFrom<>(metric, target); String mostSimilar = null; Integer shortestDistance = null; for (final String test : new String[] { "Appaloosa", "a patchy", "apple" }) { final Integer distance = metricFrom.apply(test); if (shortestDistance == null || distance < shortestDistance) { shortestDistance = distance; mostSimilar = test; } } assertEquals("a patchy", mostSimilar); assertEquals(4, shortestDistance); } @Test void testMissingMetric() { assertThrows(IllegalArgumentException.class, () -> new EditDistanceFrom(null, "no go")); } } commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/000077500000000000000000000000001511432740600306045ustar00rootroot00000000000000AggregateTranslatorTest.java000066400000000000000000000052611511432740600361740ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; /** * Tests {@link AggregateTranslator}. */ class AggregateTranslatorTest { @Test void testNonNull() throws IOException { final Map oneTwoMap = new HashMap<>(); oneTwoMap.put("one", "two"); final Map threeFourMap = new HashMap<>(); threeFourMap.put("three", "four"); final CharSequenceTranslator translator1 = new LookupTranslator(oneTwoMap); final CharSequenceTranslator translator2 = new LookupTranslator(threeFourMap); final AggregateTranslator subject = new AggregateTranslator(translator1, translator2); final StringWriter out1 = new StringWriter(); final int result1 = subject.translate(new StringBuffer("one"), 0, out1); assertEquals(3, result1, "Incorrect code point consumption"); assertEquals("two", out1.toString()); final StringWriter out2 = new StringWriter(); final int result2 = subject.translate(new StringBuffer("three"), 0, out2); assertEquals(5, result2, "Incorrect code point consumption"); assertEquals("four", out2.toString(), "Incorrect value"); } @Test void testNullConstructor() { final String testString = "foo"; final AggregateTranslator subject = new AggregateTranslator((CharSequenceTranslator[]) null); assertEquals(testString, subject.translate(testString)); } @Test void testNullVarargConstructor() { final String testString = "foo"; final AggregateTranslator subject = new AggregateTranslator((CharSequenceTranslator) null); assertEquals(testString, subject.translate(testString)); } } CharSequenceTranslatorTest.java000066400000000000000000000041431511432740600366520ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.Writer; import org.junit.jupiter.api.Test; class CharSequenceTranslatorTest { private final class TestCharSequenceTranslator extends CharSequenceTranslator { @Override public int translate(final CharSequence input, final int index, final Writer writer) { translateInvocationCounter++; return 0; } } //Used to count translate invocations private int translateInvocationCounter; @Test void testWith() throws IOException { final CharSequenceTranslator charSequenceTranslatorOne = new TestCharSequenceTranslator(); final CharSequenceTranslator charSequenceTranslatorTwo = new TestCharSequenceTranslator(); final CharSequenceTranslator charSequenceTranslatorThree = new TestCharSequenceTranslator(); final CharSequenceTranslator aggregatedTranslator = charSequenceTranslatorOne.with(charSequenceTranslatorTwo, charSequenceTranslatorThree); aggregatedTranslator.translate("", 0, null); assertTrue(aggregatedTranslator instanceof AggregateTranslator); assertEquals(3, translateInvocationCounter); } } CodePointTranslatorTest.java000066400000000000000000000030441511432740600361670ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.io.PipedReader; import java.io.PipedWriter; import org.junit.jupiter.api.Test; class CodePointTranslatorTest { @Test void testAboveReturningNonNull() throws IOException { final NumericEntityEscaper numericEntityEscaper = NumericEntityEscaper.above(0); final UnicodeEscaper unicodeEscaper = new UnicodeEscaper(); final String string = unicodeEscaper.toUtf16Escape(0); try (PipedReader pipedReader = new PipedReader(); PipedWriter pipedWriter = new PipedWriter(pipedReader)) { assertEquals(1, numericEntityEscaper.translate(string, 0, pipedWriter)); } } } CsvTranslatorsTest.java000066400000000000000000000123221511432740600352200ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import org.apache.commons.lang3.CharUtils; import org.junit.jupiter.api.Test; class CsvTranslatorsTest { @Test void testCsvEscaperCommaTest() throws IOException { final CsvTranslators.CsvEscaper escaper = new CsvTranslators.CsvEscaper(); final Writer writer = new StringWriter(); final String input = "hi,this,is,a,test"; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals("\"hi,this,is,a,test\"", data); } @Test void testCsvEscaperCRTest() throws IOException { final CsvTranslators.CsvEscaper escaper = new CsvTranslators.CsvEscaper(); final Writer writer = new StringWriter(); final String input = "hi,this,is,a,CR,test" + String.valueOf(CharUtils.CR); escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals("\"hi,this,is,a,CR,test" + String.valueOf(CharUtils.CR) + "\"", data); } @Test void testCsvEscaperLFTest() throws IOException { final CsvTranslators.CsvEscaper escaper = new CsvTranslators.CsvEscaper(); final Writer writer = new StringWriter(); final String input = "hi,this,is,a,LF,test" + String.valueOf(CharUtils.LF); escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals("\"hi,this,is,a,LF,test" + String.valueOf(CharUtils.LF) + "\"", data); } @Test void testCsvEscaperPlaneTextTest() throws IOException { final CsvTranslators.CsvEscaper escaper = new CsvTranslators.CsvEscaper(); final Writer writer = new StringWriter(); final String input = "hi this is just a plane text nothing to do with csv!"; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals(data, input); } @Test void testCsvEscaperQuoteTest() throws IOException { final CsvTranslators.CsvEscaper escaper = new CsvTranslators.CsvEscaper(); final Writer writer = new StringWriter(); final String input = "hi,this,is,a,\"quote,test"; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals("\"hi,this,is,a,\"\"quote,test\"", data); } @Test void testCsvUnEscaperPlaneTextTest() throws IOException { final CsvTranslators.CsvUnescaper escaper = new CsvTranslators.CsvUnescaper(); final Writer writer = new StringWriter(); final String input = "hi,this,is,unescape,test"; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals(input, data); } @Test void testCsvUnEscaperTest1() throws IOException { final CsvTranslators.CsvUnescaper escaper = new CsvTranslators.CsvUnescaper(); final Writer writer = new StringWriter(); final String input = "\"hi,this,is,unescape,test\""; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals("hi,this,is,unescape,test", data); } @Test void testCsvUnEscaperTest2() throws IOException { final CsvTranslators.CsvUnescaper escaper = new CsvTranslators.CsvUnescaper(); final Writer writer = new StringWriter(); final String input = "\"hi,this,is,unescape,test"; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals(input, data); } @Test void testCsvUnEscaperTest3() throws IOException { final CsvTranslators.CsvUnescaper escaper = new CsvTranslators.CsvUnescaper(); final Writer writer = new StringWriter(); final String input = "hi,this,is,unescape,test\""; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals(input, data); } @Test void testCsvUnEscaperTest4() throws IOException { final CsvTranslators.CsvUnescaper escaper = new CsvTranslators.CsvUnescaper(); final Writer writer = new StringWriter(); final String input = "\"hi,this,is,\"unescape,test\""; escaper.translateWhole(input, writer); final String data = writer.toString(); assertEquals("hi,this,is,\"unescape,test", data); } } EntityArraysTest.java000066400000000000000000000112261511432740600346700ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.BufferedReader; import java.io.FileReader; import java.util.Map; import org.junit.jupiter.api.Test; /** * Tests {@link EntityArrays}. */ class EntityArraysTest { @Test void testAposMap() { testEscapeVsUnescapeMaps(EntityArrays.APOS_ESCAPE, EntityArrays.APOS_UNESCAPE); } @Test void testBasicMap() { testEscapeVsUnescapeMaps(EntityArrays.BASIC_ESCAPE, EntityArrays.BASIC_UNESCAPE); } @Test void testConstructorExists() { new EntityArrays(); } private void testEscapeVsUnescapeMaps(final Map escapeMap, final Map unescapeMap) { for (final CharSequence escapeKey : escapeMap.keySet()) { for (final CharSequence unescapeKey : unescapeMap.keySet()) { if (escapeKey == unescapeMap.get(unescapeKey)) { assertEquals(escapeMap.get(escapeKey), unescapeKey); } } } } // LANG-659, LANG-658 - avoid duplicate entries @Test void testForDuplicatedDeclaredMapKeys() throws Exception { final String packageDirectory = EntityArraysTest.class.getPackage().getName().replace(".", "/"); try (BufferedReader br = new BufferedReader(new FileReader("src/main/java/" + packageDirectory + "/EntityArrays.java"))) { String line; int mapDeclarationCounter = 0; while ((line = br.readLine()) != null) { // Start with map declaration and count put lines if (line.contains("new HashMap<>();")) { mapDeclarationCounter = 0; } else if (line.contains(".put(")) { mapDeclarationCounter++; } else if (line.contains("Collections.unmodifiableMap(initialMap);")) { final String mapVariableName = line.split("=")[0].trim(); @SuppressWarnings("unchecked") // This is test code final Map mapValue = (Map) EntityArrays.class.getDeclaredField(mapVariableName).get(EntityArrays.class); // Validate that we are not inserting into the same key twice in the map declaration. If this, // indeed was the case the keySet().size() would be smaller than the number of put() statements assertEquals(mapDeclarationCounter, mapValue.size()); } } } } @Test void testForDuplicateDeclaredMapValuesAposMap() { assertEquals(EntityArrays.APOS_UNESCAPE.size(), EntityArrays.APOS_ESCAPE.size()); } @Test void testForDuplicateDeclaredMapValuesBasicMap() { assertEquals(EntityArrays.BASIC_ESCAPE.size(), EntityArrays.BASIC_UNESCAPE.size()); } @Test void testForDuplicateDeclaredMapValuesHtml40ExtendedMap() { assertEquals(EntityArrays.HTML40_EXTENDED_ESCAPE.size(), EntityArrays.HTML40_EXTENDED_UNESCAPE.size()); } @Test void testForDuplicateDeclaredMapValuesISO8859Map() { assertEquals(EntityArrays.ISO8859_1_ESCAPE.size(), EntityArrays.ISO8859_1_UNESCAPE.size()); } @Test void testForDuplicateDeclaredMapValuesJavaCtrlCharsMap() { assertEquals(EntityArrays.JAVA_CTRL_CHARS_ESCAPE.size(), EntityArrays.JAVA_CTRL_CHARS_UNESCAPE.size()); } @Test void testHtml40ExtendedMap() { testEscapeVsUnescapeMaps(EntityArrays.HTML40_EXTENDED_ESCAPE, EntityArrays.HTML40_EXTENDED_UNESCAPE); } @Test void testISO8859Map() { testEscapeVsUnescapeMaps(EntityArrays.ISO8859_1_ESCAPE, EntityArrays.ISO8859_1_UNESCAPE); } @Test void testJavaCtrlCharsMap() { testEscapeVsUnescapeMaps(EntityArrays.JAVA_CTRL_CHARS_ESCAPE, EntityArrays.JAVA_CTRL_CHARS_UNESCAPE); } } JavaUnicodeEscaperTest.java000066400000000000000000000046731511432740600357350ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; /** * Tests {@link JavaUnicodeEscaper}. */ class JavaUnicodeEscaperTest { @Test void testAbove() { final JavaUnicodeEscaper jue = JavaUnicodeEscaper.above('F'); final String input = "ADFGZ"; final String result = jue.translate(input); assertEquals("ADF\\u0047\\u005A", result, "Failed to escape Unicode characters via the above method"); } @Test void testBelow() { final JavaUnicodeEscaper jue = JavaUnicodeEscaper.below('F'); final String input = "ADFGZ"; final String result = jue.translate(input); assertEquals("\\u0041\\u0044FGZ", result, "Failed to escape Unicode characters via the below method"); } @Test void testBetween() { final JavaUnicodeEscaper jue = JavaUnicodeEscaper.between('F', 'L'); final String input = "ADFGZ"; final String result = jue.translate(input); assertEquals("AD\\u0046\\u0047Z", result, "Failed to escape Unicode characters via the between method"); } @Test void testToUtf16Escape() { final JavaUnicodeEscaper jue = JavaUnicodeEscaper.below('F'); // According to https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B10000..U.2B10FFFF, // Character ?, U+24B62, Binary Code Point 0010 0100 1011 0110 0010, // Binary UTF-167 1101 1000 0101 0010 1101 1111 0110 0010, UTF-16 Hex Code Units D852 DF62 final String encoding = jue.toUtf16Escape(Integer.parseInt("024B62", 16)); assertEquals("\\uD852\\uDF62", encoding); } } LookupTranslatorTest.java000066400000000000000000000060261511432740600355570ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import java.io.IOException; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; /** * Tests {@link LookupTranslator}. */ class LookupTranslatorTest { @Test void testBasicLookup() throws IOException { final Map translatorMap = new HashMap<>(); translatorMap.put("one", "two"); final LookupTranslator lt = new LookupTranslator(translatorMap); final StringWriter out = new StringWriter(); final int result = lt.translate("one", 0, out); assertEquals(3, result, "Incorrect code point consumption"); assertEquals("two", out.toString(), "Incorrect value"); } @Test void testFailsToCreateLookupTranslatorThrowsInvalidParameterException() { assertThrowsExactly(NullPointerException.class, () -> new LookupTranslator(null)); } // Tests: https://issues.apache.org/jira/browse/LANG-882 @Test void testLang882() throws IOException { final Map translatorMap = new HashMap<>(); translatorMap.put(new StringBuffer("one"), new StringBuffer("two")); final LookupTranslator lt = new LookupTranslator(translatorMap); final StringWriter out = new StringWriter(); final int result = lt.translate(new StringBuffer("one"), 0, out); assertEquals(3, result, "Incorrect code point consumption"); assertEquals("two", out.toString(), "Incorrect value"); } @Test void testTranslateSupplementaryCharacter() { /* Key: string with Mathematical double-struck capital A (U+1D538) */ final String symbol = new StringBuilder().appendCodePoint(0x1D538).toString(); /* Map U+1D538 to "A" */ final Map map = new HashMap<>(); map.put(symbol, "A"); final LookupTranslator translator = new LookupTranslator(map); final String translated = translator.translate(symbol + "=A"); /* we should get "A=A". */ assertEquals("A=A", translated, "Incorrect value"); } } NumericEntityEscaperTest.java000066400000000000000000000044641511432740600363420ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; /** * Tests {@link NumericEntityEscaper}. */ class NumericEntityEscaperTest { @Test void testAbove() { final NumericEntityEscaper nee = NumericEntityEscaper.above('F'); final String input = "ADFGZ"; final String result = nee.translate(input); assertEquals("ADFGZ", result, "Failed to escape numeric entities via the above method"); } @Test void testBelow() { final NumericEntityEscaper nee = NumericEntityEscaper.below('F'); final String input = "ADFGZ"; final String result = nee.translate(input); assertEquals("ADFGZ", result, "Failed to escape numeric entities via the below method"); } @Test void testBetween() { final NumericEntityEscaper nee = NumericEntityEscaper.between('F', 'L'); final String input = "ADFGZ"; final String result = nee.translate(input); assertEquals("ADFGZ", result, "Failed to escape numeric entities via the between method"); } /** See LANG-617 */ @Test void testSupplementary() { final NumericEntityEscaper nee = new NumericEntityEscaper(); final String input = "\uD803\uDC22"; final String expected = "𐰢"; final String result = nee.translate(input); assertEquals(expected, result, "Failed to escape numeric entities supplementary characters"); } } NumericEntityUnescaperTest.java000066400000000000000000000074001511432740600366760ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import org.junit.jupiter.api.Test; /** * Tests {@link NumericEntityUnescaper}. */ class NumericEntityUnescaperTest { @Test void testCreatesNumericEntityUnescaperOne() { final NumericEntityUnescaper.OPTION[] numericEntityUnescaperOPTIONArray = {}; final NumericEntityUnescaper numericEntityUnescaper = new NumericEntityUnescaper(numericEntityUnescaperOPTIONArray); assertEquals("2|y|O7y`&#uVWj", numericEntityUnescaper.translate("2|y|O7y`&#uVWj")); } @Test void testCreatesNumericEntityUnescaperTwo() { final NumericEntityUnescaper.OPTION[] numericEntityUnescaperOPTIONArray = {}; final NumericEntityUnescaper numericEntityUnescaper = new NumericEntityUnescaper(numericEntityUnescaperOPTIONArray); assertEquals("Ws2v8|O=7NR&#cB", numericEntityUnescaper.translate("Ws2v8|O=7NR&#cB")); } @Test void testOutOfBounds() { final NumericEntityUnescaper neu = new NumericEntityUnescaper(); assertEquals("Test &", neu.translate("Test &"), "Failed to ignore when last character is &"); assertEquals("Test &#", neu.translate("Test &#"), "Failed to ignore when last character is &"); assertEquals("Test &#x", neu.translate("Test &#x"), "Failed to ignore when last character is &"); assertEquals("Test &#X", neu.translate("Test &#X"), "Failed to ignore when last character is &"); } @Test void testSupplementaryUnescaping() { final NumericEntityUnescaper neu = new NumericEntityUnescaper(); final String input = "𐰢"; final String expected = "\uD803\uDC22"; final String result = neu.translate(input); assertEquals(expected, result, "Failed to unescape numeric entities supplementary characters"); } @Test void testUnfinishedEntity() { // parse it NumericEntityUnescaper neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional); String input = "Test 0 not test"; String expected = "Test \u0030 not test"; String result = neu.translate(input); assertEquals(expected, result, "Failed to support unfinished entities (i.e. missing semicolon)"); // ignore it neu = new NumericEntityUnescaper(); input = "Test 0 not test"; expected = input; result = neu.translate(input); assertEquals(expected, result, "Failed to ignore unfinished entities (i.e. missing semicolon)"); // fail it neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon); input = "Test 0 not test"; try { result = neu.translate(input); fail("IllegalArgumentException expected"); } catch (final IllegalArgumentException iae) { // expected } } } OctalUnescaperTest.java000066400000000000000000000061601511432740600351430ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; /** * Tests {@link OctalUnescaper}. */ class OctalUnescaperTest { @Test void testBetween() { final OctalUnescaper oue = new OctalUnescaper(); // .between("1", "377"); String input = "\\45"; String result = oue.translate(input); assertEquals("\45", result, "Failed to unescape octal characters via the between method"); input = "\\377"; result = oue.translate(input); assertEquals("\377", result, "Failed to unescape octal characters via the between method"); input = "\\377 and"; result = oue.translate(input); assertEquals("\377 and", result, "Failed to unescape octal characters via the between method"); input = "\\378 and"; result = oue.translate(input); assertEquals("\37" + "8 and", result, "Failed to unescape octal characters via the between method"); input = "\\378"; result = oue.translate(input); assertEquals("\37" + "8", result, "Failed to unescape octal characters via the between method"); input = "\\1"; result = oue.translate(input); assertEquals("\1", result, "Failed to unescape octal characters via the between method"); input = "\\036"; result = oue.translate(input); assertEquals("\036", result, "Failed to unescape octal characters via the between method"); input = "\\0365"; result = oue.translate(input); assertEquals("\036" + "5", result, "Failed to unescape octal characters via the between method"); input = "\\003"; result = oue.translate(input); assertEquals("\003", result, "Failed to unescape octal characters via the between method"); input = "\\0003"; result = oue.translate(input); assertEquals("\000" + "3", result, "Failed to unescape octal characters via the between method"); input = "\\279"; result = oue.translate(input); assertEquals("\279", result, "Failed to unescape octal characters via the between method"); input = "\\999"; result = oue.translate(input); assertEquals("\\999", result, "Failed to ignore an out of range octal character via the between method"); } } SinglePassTranslatorTest.java000066400000000000000000000042071511432740600363550ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * Unit test for {@link SinglePassTranslator}. */ class SinglePassTranslatorTest { private final SinglePassTranslator dummyTranslator = new SinglePassTranslator() { @Override void translateWhole(final CharSequence input, final Writer writer) throws IOException { // noop } }; private StringWriter out; @BeforeEach public void before() { out = new StringWriter(); } @Test void testCodePointsAreReturned() throws Exception { assertEquals(0, dummyTranslator.translate("", 0, out)); assertEquals(3, dummyTranslator.translate("abc", 0, out)); assertEquals(7, dummyTranslator.translate("abcdefg", 0, out)); } @Test void testIndexIsValidated() { assertThrows(IllegalArgumentException.class, () -> dummyTranslator.translate("abc", 1, out)); } @Test void testTranslateThrowsIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> dummyTranslator.translate("(,Fk", 647, null)); } } UnicodeEscaperTest.java000066400000000000000000000036511511432740600351260ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; /** * Tests {@link UnicodeEscaper}. */ class UnicodeEscaperTest { @Test void testAbove() { final UnicodeEscaper escaper = UnicodeEscaper.above('F'); final String input = "ADFGZ"; final String result = escaper.translate(input); assertEquals("ADF\\u0047\\u005A", result, "Failed to escape Unicode characters via the above method"); } @Test void testBelow() { final UnicodeEscaper escaper = UnicodeEscaper.below('F'); final String input = "ADFGZ"; final String result = escaper.translate(input); assertEquals("\\u0041\\u0044FGZ", result, "Failed to escape Unicode characters via the below method"); } @Test void testBetween() { final UnicodeEscaper escaper = UnicodeEscaper.between('F', 'L'); final String input = "ADFGZ"; final String result = escaper.translate(input); assertEquals("AD\\u0046\\u0047Z", result, "Failed to escape Unicode characters via the between method"); } } UnicodeUnescaperTest.java000066400000000000000000000036001511432740600354630ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; /** * Tests {@link UnicodeEscaper}. */ class UnicodeUnescaperTest { @Test void testLessThanFour() { final UnicodeUnescaper escaper = new UnicodeUnescaper(); final String input = "\\0047\\u006"; assertThrows(IllegalArgumentException.class, () -> escaper.translate(input)); } // Requested in LANG-507 @Test void testUPlus() { final UnicodeUnescaper escaper = new UnicodeUnescaper(); final String input = "\\u+0047"; assertEquals("G", escaper.translate(input), "Failed to unescape Unicode characters with 'u+' notation"); } @Test void testUuuuu() { final UnicodeUnescaper escaper = new UnicodeUnescaper(); final String input = "\\uuuuuuuu0047"; final String result = escaper.translate(input); assertEquals("G", result, "Failed to unescape Unicode characters with many 'u' characters"); } } UnicodeUnpairedSurrogateRemoverTest.java000066400000000000000000000034771511432740600405550ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/java/org/apache/commons/text/translate/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.text.translate; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.CharArrayWriter; import java.io.IOException; import org.junit.jupiter.api.Test; /** * Tests {@link UnicodeUnpairedSurrogateRemover}. */ class UnicodeUnpairedSurrogateRemoverTest { final UnicodeUnpairedSurrogateRemover subject = new UnicodeUnpairedSurrogateRemover(); final CharArrayWriter writer = new CharArrayWriter(); // nothing is ever written to it @Test void testInvalidCharacters() throws IOException { assertTrue(subject.translate(0xd800, writer)); assertTrue(subject.translate(0xdfff, writer)); assertEquals(0, writer.size()); } @Test void testValidCharacters() throws IOException { assertFalse(subject.translate(0xd7ff, writer)); assertFalse(subject.translate(0xe000, writer)); assertEquals(0, writer.size()); } } commons-text-rel-commons-text-1.15.0/src/test/resources/000077500000000000000000000000001511432740600232315ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/000077500000000000000000000000001511432740600240205ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/000077500000000000000000000000001511432740600252415ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/000077500000000000000000000000001511432740600267145ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/000077500000000000000000000000001511432740600277005ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/bla.xml000066400000000000000000000031471511432740600311650ustar00rootroot00000000000000 ]> &lol9; document-entity-ref.xml000066400000000000000000000020701511432740600342440ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text ]> Example of an External Entity &ext; document-external-dtd.dtd000066400000000000000000000016661511432740600345360ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text document-external-dtd.xml000066400000000000000000000020711511432740600345520ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text Example of an External Entity &externalEntity; commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/document.properties000066400000000000000000000014451511432740600336400ustar00rootroot00000000000000# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. mykey = Hello World! commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/document.xml000066400000000000000000000016471511432740600322500ustar00rootroot00000000000000 Hello World! commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/example/000077500000000000000000000000001511432740600313335ustar00rootroot00000000000000testResourceBundleLookup.properties000066400000000000000000000015541511432740600404120ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/example# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. key = value number = 2 keyWithMissingKey = ${missingKey:-defaultValue} mykey = Hello World! lcs-perf-analysis-inputs.csv000066400000000000000000000133471511432740600352220ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text"This is test data for a JMH (the Java Microbenchmark Harness) which is used from the class org.apache.commons.text.jmh.LongestCommonSubsequencePerformance." "The quick brown fox jumps over the lazy dog. A man, a plan, a canal, Panama. Was it a car or a cat I saw? Step on no pets. Rats live on no evil star." "Here, the field iterations will be populated with appropriate values from the @Param annotation by the JMH when it is passed to the benchmark method. The @Setup annotated method is invoked before each invocation of the benchmark and creates a new Hasher ensuring isolation. When the execution is finished, we'll get a result similar to the one below: When running microbenchmarks, it's very important to be aware of optimizations. Otherwise, they may affect the","benchmark results in a very misleading way. To make matters a bit more concrete, let's consider an example: We expect object allocation costs more than doing nothing at all. However, if we run the benchmarks: Apparently finding a place in the TLAB, creating and initializing an object is almost free! Just by looking at these numbers, we should know that something does not quite add up here." "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. This code is free software; you can redistribute it and/or modify it published by the Free Software Foundation. Oracle designates this This code is distributed in the hope that it will be useful, but WITHOUT FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License You should have received a copy of the GNU General Public License version","Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? under the terms of the GNU General Public License version 2 only, as particular file as subject to the *Classpath* exception as provided ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or version 2 for more details (a copy is included in the LICENSE file that 2 along with this work; if not, write to the Free Software Foundation," "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure? Here, the field iterations will be populated with appropriate values from the @Param annotation by the JMH when it is passed to the benchmark method. The @Setup annotated method is invoked before each invocation of the benchmark and creates a new Hasher ensuring isolation. When the execution is finished, we'll get a result similar to the one below: When running microbenchmarks, it's very important to be aware of optimizations. Otherwise, they may affect the","At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. benchmark results in a very misleading way. To make matters a bit more concrete, let's consider an example: We expect object allocation costs more than doing nothing at all. However, if we run the benchmarks: Apparently finding a place in the TLAB, creating and initializing an object is almost free! Just by looking at these numbers, we should know that something does not quite add up here." commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/oss-fuzz/000077500000000000000000000000001511432740600315005ustar00rootroot00000000000000clusterfuzz-testcase-StringSubstitutorInterpolatorFuzzer-5149898315268096000066400000000000000000021330141511432740600467270ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/oss-fuzzP)prop].:}${date:\WÿW£´DDÜDWWWWSS[SSSSD?DWWWWSSWWSS&SWWWWWÿW£aSSWS:WS].!WWWWWÿSSWWSS&SWWWWWÿW£´DD?SSSaSSWS:WS].!WWWWWÿW£´DD?DWWWWSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùùaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa±aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa‹aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaam$$$$$$$$$e$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¡žžžžžžžaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa±aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa‹aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaam$$$$$$$$$e$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¦žžžžžžžaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¡žžžžžžžaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÿÿÿaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa±aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa±aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¡žžžžžžžaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÿÿÿaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa±aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa±aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¡žžžžžžžaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaÛaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa¡žžžžžžžaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaS[SSSSaS´S€SSDDÜDWWWWSS[SSSSD?DWWWWSSWWwS&SWSS&SWWWWWÿW£´DD?SSSaSSWS:WS].!WWWWWÿW£´DD?DWWWWSS[SSSSaSSSS!SS>].:}${d\„E-tae]ÿaÿÿ.!SS>].:}${d\„E-tae]ÿaÿÿ.ÿclusterfuzz-testcase-StringSubstitutorInterpolatorFuzzer-6287296750813184000066400000000000000000000015151511432740600467160ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/oss-fuzz${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:A}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}$${datE:HZH:HZH}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}$nv:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_${datE}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:_}${env:_}${eNv:_}${eNv:_}${eNv:)}:HZH${env:_}${eNv::_}${HeNv:_}ZH${eNv:_}}stringEscapeUtilsTestData.txt000066400000000000000000000136261511432740600354740ustar00rootroot00000000000000commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text[{"geonameFeatureClass":"L","values":{"eu":"Mundua","ro":"Pamânt","it":"Globo","ca":"el món","tr":"Yeryüzü","no":"Jorden","hu":"Föld","lv":"Zeme","de":"Welt","el":"ΥδÏόγειος","fi":"Maa","la":"Terra","fr":"Monde","eo":"Mondo","en":"World","ru":"ЗемлÑ","es":"el planeta","nl":"Aarde"},"geonameFeatureCode":"AREA","_id":32,"name":"","auto":true,"type":"GEO","geonameId":6295630,"valueCode":""},{"geonameFeatureClass":"L","values":{"ro":"Europa","zh":"欧洲","ca":"Europa","vi":"Châu Âu","tr":"Avrupa","no":"Europa","hu":"Európa","lv":"Eiropa","hi":"यूरोप","lt":"Europa","bs":"Evropa","ga":"an Eoraip","th":"ยุโรป","id":"Eropa","de":"Europa","fi":"Eurooppa","fr":"Europe","sv":"Europa","bg":"Европа","da":"Europa","eu":"Europa","is":"Evrópa","it":"Europa","cy":"Ewrop","ar":"أوروبا","se":"Eurohpá","he":"×ירופה","cs":"Evropa","el":"ΕυÏώπη","nb":"Europa","pl":"Europa","la":"Europa","pt":"Europa","eo":"EÅ­ropo","en":"Europe","ru":"Европа","es":"Europa","ja":"ヨーロッパ","nl":"Europa"},"geonameFeatureCode":"CONT","_id":33,"name":"","auto":true,"type":"GEO","geonameId":6255148,"valueCode":""},{"geonameFeatureClass":"A","values":{"no":"Spania","nn":"Spania","fy":"Spanje","gd":"An Spàinn","ga":"An Spáinn","oc":"Espanha","arc":"ÜܣܦܢÜÜ","fi":"Espanja","fr":"Espagne","fo":"Spania","udm":"ИÑпаниÑ","os":"ИÑпани","he":"ספרד","gn":"Epaña","gl":"España","gv":"Yn Spaainey","pl":"Hiszpania","gu":"સà«àªªà«‡àª‡àª¨","lo":"ສະເປນ","ln":"Espania","vi":"Tây Ban Nha","dz":"Spain","pms":"Spagna","lv":"SpÄnija","lt":"Ispanija","vo":"Spanyän","de":"Spanien","mg":"Espaina","fur":"Spagne","mk":"Шпанија","ml":"à´¸àµà´ªàµ†à´¯àµà´¨àµ\u200D","ceb":"Espanya","mi":"PÄniora","uk":"ІÑпаніÑ","eu":"Espainia","mr":"सà¥à¤ªà¥‡à¤¨","ug":"ئىسپانىيە","mt":"Spanja","ms":"Sepanyol","ur":"سپین","fa":"اسپانیا","ty":"Paniora","new":"सà¥à¤ªà¥‡à¤¨","na":"Pain","el":"Ισπανία","nb":"Spania","ne":"सà¥à¤ªà¥‡à¤¨","vls":"Spanje","eo":"Hispanio","en":"Kingdom of Spain","et":"Hispaania","es":"la Madre Patria","nl":"Spanje","vec":"Spagna","to":"Sepeni","ca":"Espanya","tl":"Espanya","tr":"İspanya","tg":"ИÑпониё","haw":"Sepania","bs":"Å panija","br":"Spagn","th":"ประเทศสเปน","bn":"সà§à¦ªà§‡à¦¨","bo":"སི་པནà¼","ta":"ஸà¯à®ªà¯†à®¯à®¿à®©à¯","sv":"Spanien","bg":"ИÑпаниÑ","ka":"ესპáƒáƒœáƒ”თი","st":"Spain","sw":"Hispania","be":"ІÑпаніÑ","kw":"Spayn","sl":"Å panija","sk":"Å panielsko","da":"Spanien","ang":"SpÄ“onland","nds":"Spanien","ks":"SpÄ“na","so":"Isbeyn","ku":"Spanya","sr":"Шпанија","sq":"Spanja","ko":"ì—스파ëƒ","sc":"Ispagna","cy":"Sbaen","se":"Espánjja","sh":"Å panija","cv":"ИÑпани","km":"អáŸážŸáŸ’ប៉ាញ","cs":"Å panÄ›lsko","li":"Spanje","co":"Spagna","default":"Spain","jbo":"sangu'e","la":"Hesperia","ru":"ИÑпаниÑ","lb":"Spuenien","sco":"Spain","tet":"España","scn":"Spagna","hr":"Å panjolska","zh":"西ç­ç‰™","ro":"Spania","rm":"Spagna","ht":"Espay","hu":"Spanyolország","ast":"España","hi":"सà¥à¤ªà¥‡à¤¨","hsb":"Å paniska","nah":"CaxtillÄn","war":"Espanya","lad":"Espanya","id":"Spanyol","ia":"Espania","nrm":"Espangne","hy":"Ô»Õ½ÕºÕ¡Õ¶Õ«Õ¡","qu":"Ispaña","ilo":"Espania","az":"İspaniya","is":"Spánn","it":"Spagna","tpi":"Spen","ar":"أسبانيا","io":"Hispania","pam":"Espanya","frp":"Èspagne","am":"እስá“ንያ","an":"España","csb":"SzpaÅ„skô","pt":"Espanha","ja":"スペイン","ps":"اسپانيا","yi":"שפ×× ×™×¢","af":"Spanje"},"geonameFeatureCode":"PCLI","_id":260,"name":"","auto":true,"type":"GEO","geonameId":2510769,"valueCode":""},{"geonameFeatureClass":"A","values":{"ca":"Andalusia","tr":"Endülüs","krc":"ÐндалуÑиÑ","no":"Andalucía","fy":"Andalûsje","bs":"Andaluzija","br":"Andalouzia","ext":"Andaluzia","ga":"An Andalúis","th":"à¹à¸„ว้นอันดาลูซีอา","bn":"আনà§à¦¦à¦¾à¦²à§à¦¸à¦¿à¦¯à¦¼à¦¾","oc":"Andalosia","ka":"áƒáƒœáƒ“áƒáƒšáƒ£áƒ¡áƒ˜áƒ","sv":"Andalusien","fr":"Andalousie","bg":"ÐндалуÑиÑ","glk":"آندالوسیا","be":"ÐндалуÑÑ–Ñ","kw":"Andalousi","sk":"Andalúzia","os":"ÐндалуÑи","da":"Andalusien","sr":"Ðндалузија","ku":"Endulus","ko":"안달루시아 지방","he":"×נדלוסיה","sh":"Andaluzija","arz":"اندلوسيا","cs":"Andalusie","default":"Andalusia","stq":"Andalusien","la":"Vandalitia","pl":"Andaluzja","ru":"ÐндалуÑиÑ","lb":"Andalusien","tet":"Andaluzia","got":"ð…ðŒ°ðŒ½ðŒ³ðŒ°ðŒ»ðŒ¹ð„ðŒ¾ðŒ°","hr":"Andaluzija","zh":"安é”魯西亞","ro":"Andaluzia","hu":"Andalúzia","pms":"Andalusìa","lv":"AndalÅ«zija","lt":"AndalÅ«zija","nah":"Andalucia","lad":"Andaluziya","de":"Andalusien","als":"Andalusien","qu":"Andalusiya","hy":"Ô±Õ¶Õ¤Õ¡Õ¬Õ¸Ö‚Õ¦Õ«Õ¡","eu":"Andaluzia","is":"Andalúsía","uk":"ÐндалуÑÑ–Ñ","az":"Andalusiya","mr":"आंदालà¥à¤¸à¤¿à¤¯à¤¾","ug":"Andalusiye","fa":"اندلس","ar":"أندلوسيا","rmy":"Andalusiya","io":"Andaluzia","el":"Ανδαλουσία","frp":"Andalosie","pt":"Andaluzia","eo":"Andaluzio","en":"Andalusia","et":"Andaluusia","es":"Andalucía","ja":"アンダルシア州","nl":"Andalusië","af":"Andalusië","vec":"Andalusìa"},"geonameFeatureCode":"ADM1","_id":261,"name":"","auto":true,"type":"GEO","geonameId":2593109,"valueCode":""},{"geonameFeatureClass":"A","values":{"de":"Granada","default":"Province of Granada","fr":"Grenade","en":"Province of Granada","es":"Provincia de Granada","ja":"グラナダ"},"geonameFeatureCode":"ADM2","_id":262,"name":"","auto":true,"type":"GEO","geonameId":2517115,"valueCode":""},{"geonameFeatureClass":"A","values":{"default":"Monachil"},"geonameFeatureCode":"ADM3","_id":263,"name":"","auto":true,"type":"GEO","geonameId":6357744,"valueCode":""},{"geonameFeatureClass":"P","values":{"default":"Sierra Nevada"},"geonameFeatureCode":"PPL","_id":264,"name":"","auto":true,"type":"GEO","geonameId":6544329,"valueCode":""}]commons-text-rel-commons-text-1.15.0/src/test/resources/org/apache/commons/text/xml-entity.txt000066400000000000000000000015111511432740600325510ustar00rootroot00000000000000 Hello World!