├── .github ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE │ └── pull_request.md ├── SECURITY.md ├── pplx-logo-dark.png ├── pplx-logo-light.png └── version.json ├── .gitignore ├── LICENSE ├── README.md ├── cli.py ├── client.py ├── config.py ├── example.env ├── examples ├── example_chat.py └── example_search.py ├── loading.py ├── perplexity.py └── requirements.txt /.github/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to the project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.2.2] - 2024-05-05 8 | 9 | ### Added 10 | - Added support for `llama-3-sonar-small-32k-chat`, `llama-3-sonar-large-32k-chat`, `llama-3-sonar-small-32k-online` and `llama-3-sonar-large-32k-online`. 11 | 12 | ### Changed 13 | - Updated default base models in `config.py` to use `llama-3-sonar-large-32k-chat` for chat functionalities and `llama-3-sonar-large-32k-online` for search functionalities. 14 | 15 | ### Removed 16 | - Removed references to older models such as `sonar-small-chat`, `sonar-medium-chat`, `sonar-small-online` and `sonar-medium-online` in the code and documentation to streamline the use of newer `llama-3-sonar` models. 17 | - Removed references to `codellama-70b-instruct`, `mistral-7b-instruct` and `mixtral-8x22b-instruct`, as Perplexity Labs no loger supports the models. 18 | 19 | ## [1.2.1] - 2024-04-22 20 | 21 | ### Added 22 | - Added support for `llama-3` 23 | - Added syntax for exiting/quitting the program to the beginning of the conversation in `perplexity.py` 24 | - Added goodbye syntax to the end of the search request in `perplexity.py` 25 | 26 | ### Changed 27 | - Changed variable names in `config.py` 28 | - Set default models to models from config or env in `perplexity.py` 29 | - Updated syntax in `cli.py` 30 | 31 | ### Removed 32 | - Removed unused timeout in `client.py` 33 | 34 | ## [1.2.0] - 2024-03-23 35 | 36 | ### Added 37 | - config.py: Introduced a configuration management system to load environment variables and default settings. 38 | - client.py: Implemented a new client architecture for making API requests, including streaming support. 39 | 40 | ### Improved 41 | - loading.py: No changes detected in functionality, the code remains identical. 42 | - perplexity.py: Enhanced with a modular approach separating chat and search functionalities into distinct classes with improved error handling. 43 | - cli.py: Major overhaul to CLI interface, incorporating new options and better help documentation, facilitating both chat and search operations with the new client architecture. 44 | 45 | ### Changed 46 | - Environment variable management has been centralized and now requires specific keys (`PERPLEXITY_API_KEY`, `PERPLEXITY_DEFAULT_CHAT_MODEL`, `PERPLEXITY_DEFAULT_SEARCH_MODEL`, `PERPLEXITY_BASE_URL`, `PERPLEXITY_TIMEOUT`), but has defaults already set for ease of use. 47 | - The base API interaction logic has been encapsulated within the Client class, abstracting the complexities of request handling, including streaming. 48 | 49 | ### Removed 50 | - `pplx.py`, `pplx_cli.py`, `base_api.py`, `pplx_search.py`, and `pplx_chat.py` have been replaced with the new `client.py`, `config.py`, `perplexity.py`, and `cli.py` files, indicating a structural overhaul. 51 | - The direct dependency on .env file loading within API wrapper files has been removed, now managed centrally in `config.py`. 52 | 53 | ### Fixed 54 | - The handling of API keys and configuration settings has been standardized, fixing inconsistencies in how environment variables were previously managed. 55 | 56 | ## [1.1.2] - 02/25/2024 57 | 58 | `base_api.py` 59 | 60 | ### Improved 61 | 62 | - Enhanced error handling in the post method to provide clearer error messages and gracefully exit the application upon encountering a critical error, improving user experience and debuggability. 63 | - Added a finally block to ensure that the loading animation is always stopped, even if an error occurs, preventing potential terminal display issues. 64 | - Modified the loading animation to start only in non-streaming requests to avoid overlap with streaming output, enhancing output readability. 65 | - Streamlined the API key retrieval process with a more descriptive error message if the API key is not found, aiding users in configuration setup. 66 | 67 | ### Fixed 68 | 69 | - Fixed an issue where the loading animation could potentially continue running or the cursor remained hidden if an exception was thrown during a request. 70 | - Addressed a potential bug by ensuring the terminal is cleared only on error, preserving user input and previous interactions for reference. 71 | 72 | `pplx_cli.py` 73 | 74 | ### Added 75 | 76 | -Introduced a custom argparse formatter CustomFormatter combining ArgumentDefaultsHelpFormatter and RawDescriptionHelpFormatter to improve the help text readability. 77 | - Implemented detailed command descriptions and examples in the CLI help output, providing immediate guidance to users without external documentation. 78 | 79 | ### Changed 80 | 81 | - Unified the -a, --api_key argument declaration across both chat and search commands to improve code maintainability. 82 | - Implemented a shared function to add common arguments to both chat and search parsers, reducing code duplication. 83 | - Updated argument descriptions for enhanced clarity, making it easier for users to understand the purpose and usage of each command. 84 | - Modified all argument metavariables to an empty string, streamlining the help output by removing uppercase type hints for a cleaner interface. 85 | 86 | ### Removed 87 | 88 | - Eliminated redundant argument declarations, specifically for --api_key in both chat and search subparsers, centralizing its declaration for cleaner code. 89 | 90 | ## [1.1.1] - 02/23/2024 91 | 92 | ### Added 93 | - Support for Perplexity Labs latest `sonar-small-chat`, `sonar-small-online`, `sonar-medium-chat`, and `sonar-medium-online` AI models offering improvements in cost-efficiency, speed, and performance. 94 | - Extended context window support, now accommodating up to 16k tokens for models like `mixtral-8x7b-instruct` and all Perplexity models. 95 | - Increased public rate limits across all models to accommodate approximately 2x more requests. 96 | 97 | > [!WARNING] 98 | > On March 15, the `pplx-70b-chat`, `pplx-70b-online`, `llama-2-70b-chat`, and `codellama-34b-instruct` models will no longer be available through the Perplexity API. 99 | 100 | ## [1.1.0] - 02/22/2024 101 | 102 | ### Added 103 | - loading.py for implementing a loading spinner, enhancing user experience during network requests. 104 | - base_api.py introducing BaseAPI class for shared API functionality, including request handling and streaming support. 105 | - pplx_chat.py and pplx_search.py classes, extending BaseAPI to separate concerns for chat and search functionalities. 106 | - Detailed error handling and environmental variable support for API key configuration, increasing usability and flexibility. 107 | - A comprehensive command-line interface setup in pplx_cli.py, facilitating the use of both chat and search functionalities through a unified interface. 108 | 109 | ### Changed 110 | - Modularized the codebase into separate files (pplx_cli.py, loading.py, base_api.py, pplx_chat.py, pplx_search.py), improving code organization and maintainability. 111 | - Enhanced the command-line interface with more detailed options, including model selection, temperature, top_p, top_k, presence penalty, and frequency penalty settings, allowing for a more customized user experience. 112 | - Updated the streaming functionality to use a loading spinner, providing real-time feedback during asynchronous operations. 113 | - Improved API key management by supporting environmental variables and .env files, simplifying configuration. 114 | 115 | ### Removed 116 | - The single-file script structure, replacing it with a more modular and scalable project architecture. 117 | - Direct use of requests and json in the CLI functions, moving this logic to the BaseAPI class to reduce redundancy. 118 | 119 | ### Fixed 120 | - Fixed issue where streaming was not working. 121 | - Fixed issue where command line parameters were not being set. 122 | - Fixed argument parsing structure in pplx_cli.py with subparsers for chat and search commands, enabling a more structured and versatile command-line interface. 123 | 124 | ### Security 125 | - Implemented secure API key handling through environment variables and .env files, reducing the risk of key exposure. 126 | 127 | ## [1.0.1] - 01/30/2024 128 | 129 | ### Added 130 | - Added support for new model "codellama-70b-instruct" by Meta. 131 | 132 | ## [1.0.0] - 01/10/2024 133 | 134 | ### Added 135 | - Initial release. 136 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html). -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the project 2 | 3 | We welcome contributions! This document provides guidelines and instructions for contributing to this project. 4 | 5 | ## Getting Started 6 | 7 | 1. **Fork the Repository**: Begin by forking the repository to your GitHub account. 8 | 2. **Clone the Repository**: Clone your forked repository to your local machine. 9 | 3. **Create a Branch**: Create a new branch for your contribution. 10 | 11 | ## Contribution Guidelines 12 | 13 | - **Code Style**: Follow the established code style in the project. 14 | - **Commit Messages**: Write meaningful commit messages that clearly explain the changes. 15 | - **Pull Requests**: Submit pull requests to the `main` branch. Ensure your code is well-tested and documented. 16 | 17 | ## Submitting Pull Requests 18 | 19 | 1. **Update Your Fork**: Regularly sync your fork with the main repository to keep it up-to-date. 20 | 2. **Make Your Changes**: Implement your feature or fix. 21 | 3. **Test Your Changes**: Ensure your changes do not break existing functionality. 22 | 4. **Document Your Changes**: Update the README or documentation if necessary. 23 | 5. **Submit a Pull Request**: Push your changes to your fork and open a pull request against the main repository. 24 | 25 | ## Reporting Issues 26 | 27 | - Use the GitHub issue tracker to report bugs or suggest enhancements. 28 | - Provide as much information as possible, including steps to reproduce the issue. 29 | - Check if the issue has already been reported to avoid duplicates. 30 | 31 | ## Code of Conduct 32 | 33 | By contributing to this project, you agree to abide by its [Code of Conduct](CODE_OF_CONDUCT.md). 34 | 35 | ## Questions or Suggestions 36 | 37 | Feel free to open an issue or contact the maintainers if you have any questions or suggestions. 38 | 39 | Thank you for contributing! -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pull Request 3 | about: Propose changes to the codebase 4 | title: '[PR] ' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description of the Changes** 11 | A clear and concise description of what the pull request does. 12 | 13 | **Related Issue** 14 | Link to the issue that this pull request addresses. 15 | 16 | **Motivation and Context** 17 | Why is this change required? What problem does it solve? 18 | 19 | **How Has This Been Tested?** 20 | Please describe in detail how you tested your changes. 21 | 22 | **Screenshots (if appropriate):** 23 | 24 | **Types of Changes** 25 | - [ ] Bug fix (non-breaking change which fixes an issue) 26 | - [ ] New feature (non-breaking change which adds functionality) 27 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 28 | 29 | **Checklist:** 30 | - [ ] My code follows the project's code style 31 | - [ ] I have read the CONTRIBUTING document 32 | - [ ] I have added tests to cover my changes 33 | - [ ] All new and existing tests passed 34 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 1.0.x | :white_check_mark: | 8 | | < 1.0 | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | We take the security of our software seriously. If you have discovered a security vulnerability in the project, please follow these steps to report it responsibly: 13 | 14 | 1. **Do Not Publish the Vulnerability**: Avoid sharing the details of the vulnerability in public forums, issues, or other public channels. 15 | 16 | 2. **Email the Maintainers**: Send an email to the maintainers of the project. Provide a clear description of the vulnerability, including steps to reproduce it. 17 | 18 | 3. **Wait for Response**: Allow a reasonable amount of time for the maintainers to respond to your report and address the vulnerability. 19 | 20 | 4. **Disclosure**: After the issue has been resolved and announced, you may consider disclosing the issue to the public in a responsible manner. 21 | 22 | We appreciate your efforts to responsibly disclose your findings and will make every effort to acknowledge your contributions. 23 | 24 | ## Contact Information 25 | 26 | For any security concerns, please contact us. -------------------------------------------------------------------------------- /.github/pplx-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RMNCLDYO/perplexity-ai-toolkit/c9c2680550629b80f9377cc9ccce8029a2bfeff5/.github/pplx-logo-dark.png -------------------------------------------------------------------------------- /.github/pplx-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RMNCLDYO/perplexity-ai-toolkit/c9c2680550629b80f9377cc9ccce8029a2bfeff5/.github/pplx-logo-light.png -------------------------------------------------------------------------------- /.github/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v1.2.2" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | .DS_Store 162 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 RMNCLDYO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
19 |
20 |
24 |